diff --git a/.github/install.sh b/.github/install.sh new file mode 100755 index 00000000000..047c539ff95 --- /dev/null +++ b/.github/install.sh @@ -0,0 +1,12 @@ +#!/bin/bash +sudo add-apt-repository ppa:mikhailnov/pulseeffects -y +sudo apt-get update +sudo apt-get install -y libmpfr-dev \ + libeigen3-dev qtbase5-dev libqt5sql5-sqlite libqt5opengl5-dev qtscript5-dev \ + libqt5svg5-dev qttools5-dev qttools5-dev-tools libboost1.72-dev zsh +#update cmake to 3.18.4 +sudo apt purge --auto-remove cmake +cd /tmp +wget https://cmake.org/files/v3.18/cmake-3.18.4-Linux-x86_64.sh +sudo sh cmake-3.18.4-Linux-x86_64.sh --skip-license --prefix=/usr/local +rm cmake-3.18.4-Linux-x86_64.sh diff --git a/.github/test.sh b/.github/test.sh new file mode 100755 index 00000000000..a744f6d5b08 --- /dev/null +++ b/.github/test.sh @@ -0,0 +1,13 @@ +#!/bin/bash +/usr/local/bin/cmake --version +FACTOR=$1 +set -ex +cd Polyhedron/demo +LIST_OF_PLUGINS=$(/usr/local/bin/cmake --build . -t help | egrep 'plugin$' |& cut -d\ -f2) +PLUGINS_ARRAY=(${LIST_OF_PLUGINS}); +NB_OF_PLUGINS=${#PLUGINS_ARRAY[@]} +DEL=$(($NB_OF_PLUGINS / 4)) +mkdir build +cd build +/usr/local/bin/cmake -DCGAL_DIR=$2 ../Polyhedron +make -j2 ${PLUGINS_ARRAY[@]:$(($FACTOR * $DEL)):$((($FACTOR + 1) * $DEL))} diff --git a/.github/workflows/build_doc.yml b/.github/workflows/build_doc.yml index f9ffde5ab1d..4956425db38 100644 --- a/.github/workflows/build_doc.yml +++ b/.github/workflows/build_doc.yml @@ -18,7 +18,11 @@ jobs: if(asso == 'OWNER' || asso == 'MEMBER') { const body = context.payload.comment.body if(body.includes("build:")) { - return body.replace('build:','') + const re = /\/build:(\w+)\s*/; + if(re.test(body)){ + const res = re.exec(body) + return res[1]; + } } } return 'stop' @@ -38,14 +42,16 @@ jobs: repository: ${{ github.repository }} ref: refs/pull/${{ steps.get_pr_number.outputs.result }}/merge token: ${{ secrets.PUSH_TO_CGAL_GITHUB_IO_TOKEN }} + fetch-depth: 2 - name: install dependencies if: steps.get_round.outputs.result != 'stop' run: | set -x - sudo apt-get install -y graphviz ssh - sudo pip install lxml pyquery + sudo apt-get update && sudo apt-get install -y graphviz ssh bibtex2html + sudo pip install lxml + sudo pip install 'pyquery==1.4.1' # it seems to be the last py2 compatible version wget --no-verbose -O doxygen_exe https://cgal.geometryfactory.com/~mgimeno/doxygen/build_1_8_13/bin/doxygen sudo mv doxygen_exe /usr/bin/doxygen sudo chmod +x /usr/bin/doxygen @@ -56,10 +62,9 @@ jobs: if: steps.get_round.outputs.result != 'stop' run: | set -ex - git clone https://CGAL:${{ secrets.PUSH_TO_CGAL_GITHUB_IO_TOKEN }}@github.com/CGAL/cgal.github.io.git --depth=5 mkdir -p build_doc && cd build_doc && cmake ../Documentation/doc - - name: Upload Doc + - name: Build and Upload Doc if: steps.get_round.outputs.result != 'stop' run: | set -ex @@ -67,14 +72,27 @@ jobs: ROUND=${{ steps.get_round.outputs.result }} wget --no-verbose cgal.github.io -O tmp.html if ! egrep -q "\/$PR_NUMBER\/$ROUND" tmp.html; then - mkdir -p cgal.github.io/${PR_NUMBER}/$ROUND + #list impacted packages + LIST_OF_PKGS=$(git diff --name-only HEAD^1 HEAD |cut -s -d/ -f1 |sort -u | xargs -I {} ls -d {}/package_info 2>/dev/null |cut -d/ -f1 |egrep -v Installation||true) + if [ "$LIST_OF_PKGS" = "" ]; then + exit 1 + fi cd build_doc && make -j2 doc && make -j2 doc_with_postprocessing - cp -r ./doc_output/* ../cgal.github.io/${PR_NUMBER}/$ROUND - cd ../cgal.github.io - egrep -v " ${PR_NUMBER}\." index.html > tmp.html + cd .. + git clone https://CGAL:${{ secrets.PUSH_TO_CGAL_GITHUB_IO_TOKEN }}@github.com/CGAL/cgal.github.io.git + mkdir -p cgal.github.io/${PR_NUMBER}/$ROUND + for f in $LIST_OF_PKGS + do + if [ -d ./build_doc/doc_output/$f ]; then + cp -r ./build_doc/doc_output/$f ./cgal.github.io/${PR_NUMBER}/$ROUND + fi + done + cp -r ./build_doc/doc_output/Manual ./cgal.github.io/${PR_NUMBER}/$ROUND + cd ./cgal.github.io + egrep -v " ${PR_NUMBER}\." index.html > tmp.html || true echo "
  • Manual for PR ${PR_NUMBER} ($ROUND).
  • " >> ./tmp.html mv tmp.html index.html - git add ${PR_NUMBER}/$ROUND && git commit -a -m "Add ${PR_NUMBER} $ROUND" && git push -u origin master + git add ${PR_NUMBER}/$ROUND && git commit -q --amend -m "base commit" && git push -q -f -u origin master else exit 1 fi @@ -84,7 +102,7 @@ jobs: if: steps.get_round.outputs.result != 'stop' with: script: | - const address = "The documentation is built. You can find it here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/${{ steps.get_round.outputs.result }}/Manual/index.html" + const address = "The documentation is built. It will be available, after a few minutes, here : https://cgal.github.io/${{ steps.get_pr_number.outputs.result }}/${{ steps.get_round.outputs.result }}/Manual/index.html" github.issues.createComment({ owner: "CGAL", repo: "cgal", diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 00000000000..a28adb0c684 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,30 @@ +name: CMake Test Merge Branch + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2.0.0 + - name: install dependencies + run: | + .github/install.sh + set -x + sudo apt-get update && sudo apt-get install -y graphviz ssh bibtex2html + sudo pip install lxml + sudo pip install 'pyquery==1.4.1' # it seems to be the last py2 compatible version + wget --no-verbose -O doxygen_exe https://cgal.geometryfactory.com/~mgimeno/doxygen/build_1_8_13/bin/doxygen + sudo mv doxygen_exe /usr/bin/doxygen + sudo chmod +x /usr/bin/doxygen + git config --global user.email "maxime.gimeno@geometryfactory.com" + git config --global user.name "Maxime Gimeno" + + - name: Run checks + run: | + zsh Scripts/developer_scripts/test_merge_of_branch HEAD + #test dependencies + bash Scripts/developer_scripts/cgal_check_dependencies.sh --check_headers /usr/bin/doxygen + diff --git a/.github/workflows/delete_doc.yml b/.github/workflows/delete_doc.yml index c1152d37ca9..1304a7895c9 100644 --- a/.github/workflows/delete_doc.yml +++ b/.github/workflows/delete_doc.yml @@ -18,10 +18,15 @@ jobs: git clone https://maxGimeno:${{ secrets.PUSH_TO_CGAL_GITHUB_IO_TOKEN }}@github.com/CGAL/cgal.github.io.git --depth=5 PR_NUMBER=$(python -c "import json; import os; y = json.load(open(os.environ['GITHUB_EVENT_PATH'])); print(y[\"number\"])") cd cgal.github.io/ - egrep -v " ${PR_NUMBER}\." index.html > tmp.html + egrep -v " ${PR_NUMBER}\." index.html > tmp.html || true if [ -n "$(diff -q ./index.html ./tmp.html)" ]; then mv tmp.html index.html - #git rm -r ${PR_NUMBER} && git commit -a -m "Remove ${PR_NUMBER}" && git push -u origin master - git commit -a -m "Remove ${PR_NUMBER}" && git push -u origin master + fi + if [ -d ${PR_NUMBER} ]; then + git rm -r ${PR_NUMBER} + fi + #git diff exits with 1 if there is a diff + if !git diff --quiet; then + git commit -a --amend -m"base commit" && git push -f -u origin master fi diff --git a/.github/workflows/demo.yml b/.github/workflows/demo.yml new file mode 100644 index 00000000000..6d1ff88629f --- /dev/null +++ b/.github/workflows/demo.yml @@ -0,0 +1,37 @@ +name: Test Polyhedron Demo + +on: [pull_request] + +jobs: + batch_1: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2.0.0 + - name: install dependencies + run: .github/install.sh + - name: run1 + run: ./.github/test.sh 0 ${{ github.workspace }} + batch_2: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2.0.0 + - name: install dependencies + run: .github/install.sh + - name: run2 + run: ./.github/test.sh 1 ${{ github.workspace }} + batch_3: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2.0.0 + - name: install dependencies + run: .github/install.sh + - name: run3 + run: ./.github/test.sh 2 ${{ github.workspace }} + batch_4: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2.0.0 + - name: install dependencies + run: .github/install.sh + - name: run4 + run: ./.github/test.sh 3 ${{ github.workspace }} diff --git a/.gitignore b/.gitignore index 95de0b03ae9..07f7e4fc0a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ /*build* /*/*/*/build +/*/*/*/VC* +/*/*/*/GCC AABB_tree/demo/AABB_tree/AABB_demo AABB_tree/demo/AABB_tree/Makefile AABB_tree/examples/AABB_tree/*.kdev* diff --git a/.travis/build_package.sh b/.travis/build_package.sh index 12f6082c922..dc41aa16dd1 100755 --- a/.travis/build_package.sh +++ b/.travis/build_package.sh @@ -7,30 +7,6 @@ CXX_FLAGS="-DCGAL_NDEBUG -ftemplate-backtrace-limit=0" function mytime { /usr/bin/time -f "Spend time of %C: %E (real)" "$@" } - -function build_examples { - mkdir -p build-travis - cd build-travis - mytime cmake -DCGAL_DIR="/usr/local/lib/cmake/CGAL" -DCMAKE_CXX_FLAGS="${CXX_FLAGS}" .. - mytime make -j2 VERBOSE=1 -} - -function build_tests { - build_examples -} - -function build_demo { - mkdir -p build-travis - cd build-travis - EXTRA_CXX_FLAGS= - case "$CC" in - clang*) - EXTRA_CXX_FLAGS="-Werror=inconsistent-missing-override" - ;; - esac - mytime cmake -DCGAL_DIR="/usr/local/lib/cmake/CGAL" -DCGAL_DONT_OVERRIDE_CMAKE_FLAGS:BOOL=ON -DCMAKE_CXX_FLAGS="${CXX_FLAGS} ${EXTRA_CXX_FLAGS}" .. - mytime make -j2 VERBOSE=1 -} old_IFS=$IFS IFS=$' ' ROOT="$PWD/.." @@ -93,6 +69,25 @@ cd $ROOT exit 1 fi echo "Matrix is up to date." + #check if non standard cgal installation works + cd $ROOT + mkdir build_test + cd build_test + mytime cmake -DCMAKE_INSTALL_PREFIX=install/ -DCGAL_BUILD_THREE_DOC=TRUE .. + mytime make install + # test install with minimal downstream example + mkdir installtest + cd installtest + touch main.cpp + mkdir build + echo 'project(Example)' >> CMakeLists.txt + echo 'set(PROJECT_SRCS ${PROJECT_SOURCE_DIR}/main.cpp)' >> CMakeLists.txt + echo 'find_package(CGAL REQUIRED)' >> CMakeLists.txt + echo 'add_executable(${PROJECT_NAME} ${PROJECT_SRCS})' >> CMakeLists.txt + echo 'target_link_libraries(${PROJECT_NAME} CGAL::CGAL)' >> CMakeLists.txt + echo '#include "CGAL/remove_outliers.h"' >> main.cpp + cd build + mytime cmake -DCMAKE_INSTALL_PREFIX=../../install -DCGAL_BUILD_THREE_DOC=TRUE .. exit 0 fi @@ -116,7 +111,7 @@ cd $ROOT IFS=$old_IFS - if [ -n "$TRAVIS_PULL_REQUEST_BRANCH" ] && [ "$ARG" != Polyhedron_demo ]; then + if [ -n "$TRAVIS_PULL_REQUEST_BRANCH" ]; then DO_IGNORE=FALSE . $ROOT/.travis/test_package.sh "$ROOT" "$ARG" echo "DO_IGNORE is $DO_IGNORE" @@ -125,67 +120,22 @@ cd $ROOT fi fi IFS=$' ' - EXAMPLES="$ARG/examples/$ARG" - TEST="$ARG/test/$ARG" - DEMOS=$ROOT/$ARG/demo/* - - if [ -d "$ROOT/$EXAMPLES" ] - then - cd $ROOT/$EXAMPLES - if [ -f ./CMakeLists.txt ]; then - build_examples - else - for dir in ./* - do - if [ -f $dir/CMakeLists.txt ]; then - cd $ROOT/$EXAMPLES/$dir - build_examples - fi - done - fi - elif [ "$ARG" != Polyhedron_demo ]; then - echo "No example found for $ARG" + mkdir -p build-travis + cd build-travis + WITHDEMOS=ON + if [ "$ARG" = "Polyhedron" ]; then + WITHDEMOS=OFF fi + EXTRA_CXX_FLAGS= + case "$CC" in + clang*) + EXTRA_CXX_FLAGS="-Werror=inconsistent-missing-override" + ;; + esac - if [ -d "$ROOT/$TEST" ] - then - cd $ROOT/$TEST - if [ -f ./CMakeLists.txt ]; then - build_tests - else - for dir in ./* - do - if [ -f $dir/CMakeLists.txt ]; then - cd $ROOT/$TEST/$dir - build_tests - fi - done - fi - elif [ "$ARG" != Polyhedron_demo ]; then - echo "No test found for $ARG" - fi - #Packages like Periodic_3_triangulation_3 contain multiple demos - for DEMO in $DEMOS; do - DEMO=${DEMO#"$ROOT"} - echo $DEMO - #If there is no demo subdir, try in GraphicsView - if [ ! -d "$ROOT/$DEMO" ] || [ ! -f "$ROOT/$DEMO/CMakeLists.txt" ]; then - DEMO="GraphicsView/demo/$ARG" - fi - if [ "$ARG" != Polyhedron ] && [ -d "$ROOT/$DEMO" ] - then - cd $ROOT/$DEMO - build_demo - elif [ "$ARG" != Polyhedron_demo ]; then - echo "No demo found for $ARG" - fi - done - if [ "$ARG" = Polyhedron_demo ]; then - DEMO=Polyhedron/demo/Polyhedron - cd "$ROOT/$DEMO" - build_demo - fi + mytime cmake -DCMAKE_CXX_FLAGS="${CXX_FLAGS} ${EXTRA_CXX_FLAGS}" -DCGAL_DONT_OVERRIDE_CMAKE_FLAGS:BOOL=ON -DBUILD_TESTING=ON -DWITH_tests=ON -DWITH_examples=ON -DWITH_demos=$WITHDEMOS .. + mytime ctest -j2 -L $ARG'([_][A-Z]|$)' -E execution___of__ --output-on-failure done IFS=$old_IFS # Local Variables: diff --git a/AABB_tree/benchmark/AABB_tree/CMakeLists.txt b/AABB_tree/benchmark/AABB_tree/CMakeLists.txt index 1a0f49a76f4..615266f1106 100644 --- a/AABB_tree/benchmark/AABB_tree/CMakeLists.txt +++ b/AABB_tree/benchmark/AABB_tree/CMakeLists.txt @@ -2,10 +2,16 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.14) -project( AABB_traits_benchmark ) +project(AABB_traits_benchmark) -find_package(CGAL REQUIRED QUIET OPTIONAL_COMPONENTS Core ) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Core) -create_single_source_cgal_program( "test.cpp" ) -create_single_source_cgal_program( "tree_construction.cpp" ) +# google benchmark +find_package(benchmark) +if (benchmark_FOUND) + create_single_source_cgal_program("tree_creation.cpp") + target_link_libraries(tree_creation benchmark::benchmark) +endif() +create_single_source_cgal_program("test.cpp") +create_single_source_cgal_program("tree_construction.cpp") diff --git a/AABB_tree/benchmark/AABB_tree/tree_creation.cpp b/AABB_tree/benchmark/AABB_tree/tree_creation.cpp new file mode 100644 index 00000000000..aa58d5545f2 --- /dev/null +++ b/AABB_tree/benchmark/AABB_tree/tree_creation.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef CGAL::Simple_cartesian K; +typedef CGAL::Surface_mesh Surface_mesh; +typedef CGAL::AABB_face_graph_triangle_primitive Primitive; +typedef CGAL::AABB_traits Traits; +typedef CGAL::AABB_tree Tree; +typedef K::Segment_3 Segment; +typedef K::Point_3 Point_3; + + +Surface_mesh mesh; + +static void BM_TreeCreation(benchmark::State& state) +{ + for (auto _ : state) + { + benchmark::DoNotOptimize([]() { + Tree tree{mesh.faces_begin(), mesh.faces_end(), mesh}; + tree.build(); + return 0; + }()); + } +} +BENCHMARK(BM_TreeCreation); + +static void BM_Intersections(benchmark::State& state) +{ + Point_3 p(-0.5, 0.03, 0.04); + Point_3 q(-0.5, 0.04, 0.06); + + Tree tree{mesh.faces_begin(), mesh.faces_end(), mesh}; + tree.accelerate_distance_queries(); + + Segment segment_query(p, q); + for (auto _ : state) + { + benchmark::DoNotOptimize([&]() { + tree.number_of_intersected_primitives(segment_query); + Point_3 point_query(2.0, 2.0, 2.0); + Point_3 closest = tree.closest_point(point_query); + return 0; + }()); + } +} +BENCHMARK(BM_Intersections); + + +int main(int argc, char** argv) +{ + const char* default_file = "data/handle.off"; + const char* filename = argc > 2? argv[2] : default_file; + + { + std::ifstream input(filename); + input >> mesh; + } + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + + return EXIT_SUCCESS; +} diff --git a/AABB_tree/demo/AABB_tree/CMakeLists.txt b/AABB_tree/demo/AABB_tree/CMakeLists.txt index 0200865f89e..7c006dec292 100644 --- a/AABB_tree/demo/AABB_tree/CMakeLists.txt +++ b/AABB_tree/demo/AABB_tree/CMakeLists.txt @@ -1,7 +1,7 @@ # This is the CMake script for compiling the AABB tree demo. cmake_minimum_required(VERSION 3.1...3.15) -project( AABB_tree_Demo ) +project(AABB_tree_Demo) # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -17,58 +17,56 @@ if(POLICY CMP0071) endif() # Include this package's headers first -include_directories( BEFORE ./ ./include ) +include_directories(BEFORE ./ ./include) # Find CGAL and CGAL Qt5 -find_package(CGAL COMPONENTS Qt5) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) # Find Qt5 itself find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL Gui Svg) -if(CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND) +if(CGAL_Qt5_FOUND AND Qt5_FOUND) - qt5_wrap_ui( UI_FILES MainWindow.ui ) + qt5_wrap_ui(UI_FILES MainWindow.ui) include(AddFileDependencies) - qt5_generate_moc( "MainWindow.h" "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp" ) - add_file_dependencies( MainWindow_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.h" ) + qt5_generate_moc("MainWindow.h" + "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp") + add_file_dependencies(MainWindow_moc.cpp + "${CMAKE_CURRENT_SOURCE_DIR}/MainWindow.h") - qt5_generate_moc( "Viewer.h" "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp" ) - add_file_dependencies( Viewer_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.h" ) + qt5_generate_moc("Viewer.h" "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp") + add_file_dependencies(Viewer_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Viewer.h") - qt5_generate_moc( "Scene.h" "${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp" ) - add_file_dependencies( Scene_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Scene.h" ) + qt5_generate_moc("Scene.h" "${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp") + add_file_dependencies(Scene_moc.cpp "${CMAKE_CURRENT_SOURCE_DIR}/Scene.h") - qt5_add_resources ( CGAL_Qt5_RESOURCE_FILES AABB_demo.qrc ) + qt5_add_resources(CGAL_Qt5_RESOURCE_FILES AABB_demo.qrc) - add_file_dependencies( AABB_demo.cpp "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp" - "${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp" ) + add_file_dependencies( + AABB_demo.cpp "${CMAKE_CURRENT_BINARY_DIR}/MainWindow_moc.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/Viewer_moc.cpp" + "${CMAKE_CURRENT_BINARY_DIR}/Scene_moc.cpp") - add_executable ( AABB_demo AABB_demo.cpp ${UI_FILES} ${CGAL_Qt5_RESOURCE_FILES} + add_executable( + AABB_demo AABB_demo.cpp ${UI_FILES} ${CGAL_Qt5_RESOURCE_FILES} #${CGAL_Qt5_MOC_FILES} - ) + ) # Link with Qt libraries - target_link_libraries( AABB_demo PRIVATE - Qt5::OpenGL Qt5::Gui Qt5::Xml - CGAL::CGAL - CGAL::CGAL_Qt5 - ) + target_link_libraries(AABB_demo PRIVATE Qt5::OpenGL Qt5::Gui Qt5::Xml + CGAL::CGAL CGAL::CGAL_Qt5) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS AABB_demo ) + add_to_cached_list(CGAL_EXECUTABLE_TARGETS AABB_demo) include(${CGAL_MODULES_DIR}/CGAL_add_test.cmake) cgal_add_compilation_test(AABB_demo) -else (CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND) +else(CGAL_Qt5_FOUND + AND Qt5_FOUND) set(AABB_MISSING_DEPS "") - if(NOT CGAL_FOUND) - set(AABB_MISSING_DEPS "the CGAL library, ${AABB_MISSING_DEPS}") - endif() - if(NOT CGAL_Qt5_FOUND) set(AABB_MISSING_DEPS "CGAL_Qt5, ${AABB_MISSING_DEPS}") endif() @@ -77,6 +75,11 @@ else (CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND) set(AABB_MISSING_DEPS "Qt5, ${AABB_MISSING_DEPS}") endif() - message(STATUS "NOTICE: This demo requires ${AABB_MISSING_DEPS}and will not be compiled.") + message( + STATUS + "NOTICE: This demo requires ${AABB_MISSING_DEPS}and will not be compiled." + ) -endif (CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND ) +endif( + CGAL_Qt5_FOUND + AND Qt5_FOUND) diff --git a/AABB_tree/doc/AABB_tree/PackageDescription.txt b/AABB_tree/doc/AABB_tree/PackageDescription.txt index c70c2ab611a..931f14adb53 100644 --- a/AABB_tree/doc/AABB_tree/PackageDescription.txt +++ b/AABB_tree/doc/AABB_tree/PackageDescription.txt @@ -35,7 +35,7 @@ \cgalCRPSection{Primitives} - `CGAL::AABB_triangle_primitive` - `CGAL::AABB_segment_primitive` -- `CGAL::AABB_primitive` +- `CGAL::AABB_primitive` - `CGAL::AABB_halfedge_graph_segment_primitive` - `CGAL::AABB_face_graph_triangle_primitive` */ diff --git a/AABB_tree/examples/AABB_tree/CMakeLists.txt b/AABB_tree/examples/AABB_tree/CMakeLists.txt index b66f7ec5f15..9f11b3ae5c0 100644 --- a/AABB_tree/examples/AABB_tree/CMakeLists.txt +++ b/AABB_tree/examples/AABB_tree/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( AABB_tree_Examples ) +project(AABB_tree_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/AABB_tree/include/CGAL/AABB_face_graph_triangle_primitive.h b/AABB_tree/include/CGAL/AABB_face_graph_triangle_primitive.h index 6657398435c..6d12a85adef 100644 --- a/AABB_tree/include/CGAL/AABB_face_graph_triangle_primitive.h +++ b/AABB_tree/include/CGAL/AABB_face_graph_triangle_primitive.h @@ -98,7 +98,7 @@ class AABB_face_graph_triangle_primitive } public: - #ifdef DOXYGEN_RUNNING +#ifdef DOXYGEN_RUNNING /// \name Types /// @{ /*! @@ -122,18 +122,32 @@ public: If `OneFaceGraphPerTree` is CGAL::Tag_true, constructs a `Shared_data` object from a reference to the polyhedon `graph`. */ static unspecified_type construct_shared_data( FaceGraph& graph ); - #else +#else typedef typename Base::Id Id; - #endif +#endif typedef typename boost::graph_traits::face_descriptor face_descriptor; // constructors + +#ifdef DOXYGEN_RUNNING /*! + constructs a primitive. + \tparam Iterator an input iterator with `Id` as value type. + + If `VertexPointPMap` is the default of the class, an additional constructor + is available with `vppm` set to `get(vertex_point, graph)`. + */ + template + AABB_face_graph_triangle_primitive(Iterator it, const FaceGraph& graph, VertexPointPMap vppm); + + /*! constructs a primitive. If `VertexPointPMap` is the default of the class, an additional constructor is available with `vppm` set to `get(vertex_point, graph)`. */ + AABB_face_graph_triangle_primitive(face_descriptor fd, const FaceGraph& graph, VertexPointPMap vppm); +#else template AABB_face_graph_triangle_primitive(Iterator it, const FaceGraph& graph, VertexPointPMap_ vppm) : Base( Id_(make_id(*it, graph, OneFaceGraphPerTree())), @@ -141,18 +155,12 @@ public: Point_property_map(const_cast(&graph),vppm) ) {} - /*! - constructs a primitive. - If `VertexPointPMap` is the default of the class, an additional constructor - is available with `vppm` set to `get(vertex_point, graph)`. - */ AABB_face_graph_triangle_primitive(face_descriptor fd, const FaceGraph& graph, VertexPointPMap_ vppm) : Base( Id_(make_id(fd, graph, OneFaceGraphPerTree())), Triangle_property_map(const_cast(&graph),vppm), Point_property_map(const_cast(&graph),vppm) ) {} -#ifndef DOXYGEN_RUNNING template AABB_face_graph_triangle_primitive(Iterator it, const FaceGraph& graph) : Base( Id_(make_id(*it, graph, OneFaceGraphPerTree())), diff --git a/AABB_tree/include/CGAL/AABB_halfedge_graph_segment_primitive.h b/AABB_tree/include/CGAL/AABB_halfedge_graph_segment_primitive.h index 1138376df43..a86ba35caac 100644 --- a/AABB_tree/include/CGAL/AABB_halfedge_graph_segment_primitive.h +++ b/AABB_tree/include/CGAL/AABB_halfedge_graph_segment_primitive.h @@ -140,14 +140,27 @@ public: #endif typedef typename boost::graph_traits::edge_descriptor edge_descriptor; +#ifdef DOXYGEN_RUNNING /*! constructs a primitive. + \tparam Iterator is an input iterator with `Id` as value type. + This \ref AABB_tree/AABB_halfedge_graph_edge_example.cpp "example" gives a way to call this constructor using the insert-by-range method of the class `AABB_tree`. If `VertexPointPMap` is the default of the class, an additional constructor is available with `vppm` set to `boost::get(vertex_point, graph)`. */ + template + AABB_halfedge_graph_segment_primitive(Iterator it, const HalfedgeGraph& graph, VertexPointPMap vppm); + + /*! + constructs a primitive. + If `VertexPointPMap` is the default of the class, an additional constructor + is available with `vppm` set to `boost::get(vertex_point, graph)`. + */ + AABB_halfedge_graph_segment_primitive(edge_descriptor ed, const HalfedgeGraph& graph, VertexPointPMap vppm); +#else template AABB_halfedge_graph_segment_primitive(Iterator it, const HalfedgeGraph& graph, VertexPointPMap_ vppm) : Base( Id_(make_id(*it, graph, OneHalfedgeGraphPerTree())), @@ -155,18 +168,12 @@ public: Point_property_map(const_cast(&graph), vppm) ) {} - /*! - constructs a primitive. - If `VertexPointPMap` is the default of the class, an additional constructor - is available with `vppm` set to `boost::get(vertex_point, graph)`. - */ AABB_halfedge_graph_segment_primitive(edge_descriptor ed, const HalfedgeGraph& graph, VertexPointPMap_ vppm) : Base( Id_(make_id(ed, graph, OneHalfedgeGraphPerTree())), Segment_property_map(const_cast(&graph), vppm), Point_property_map(const_cast(&graph), vppm) ) {} - #ifndef DOXYGEN_RUNNING template AABB_halfedge_graph_segment_primitive(Iterator it, const HalfedgeGraph& graph) : Base( Id_(make_id(*it, graph, OneHalfedgeGraphPerTree())), @@ -177,7 +184,7 @@ public: : Base( Id_(make_id(ed, graph, OneHalfedgeGraphPerTree())), Segment_property_map(const_cast(&graph)), Point_property_map(const_cast(&graph)) ){} - #endif +#endif /// \internal typedef internal::Cstr_shared_data Cstr_shared_data; diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 03a6dab8354..5f0521e219f 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -13,6 +13,8 @@ #ifndef CGAL_AABB_TREE_H #define CGAL_AABB_TREE_H +#include + #include #include @@ -62,6 +64,7 @@ namespace CGAL { typedef std::vector Primitives; typedef internal::Primitive_helper Helper; + typedef AABB_tree Self; public: typedef AABBTraits AABB_traits; @@ -113,6 +116,15 @@ namespace CGAL { /// class using `traits`. AABB_tree(const AABBTraits& traits = AABBTraits()); + /// move constructor + AABB_tree(Self&&) noexcept; + /// assignment operator + Self& operator=(Self&&) noexcept; + + // Disabled copy constructor & assignment operator + AABB_tree(const Self&) = delete; + Self& operator=(const Self&) = delete; + /** * @brief Builds the datastructure from a sequence of primitives. * @param first iterator over first primitive to insert @@ -475,10 +487,7 @@ public: // clear nodes void clear_nodes() { - if( size() > 1 ) { - delete [] m_p_root_node; - } - m_p_root_node = nullptr; + m_nodes.clear(); } // clears internal KD tree @@ -491,8 +500,7 @@ public: #endif { CGAL_assertion( m_p_search_tree!=nullptr ); - delete m_p_search_tree; - m_p_search_tree = nullptr; + m_p_search_tree.reset(); #ifdef CGAL_HAS_THREADS m_atomic_search_tree_constructed.store(false, std::memory_order_relaxed); #else @@ -522,6 +530,22 @@ public: private: typedef AABB_node Node; + /** + * @brief Builds the tree by recursive expansion. + * @param first the first primitive to insert + * @param last the last primitive to insert + * @param range the number of primitive of the range + * + * [first,last[ is the range of primitives to be added to the tree. + */ + template + void expand(Node& node, + ConstPrimitiveIterator first, + ConstPrimitiveIterator beyond, + const std::size_t range, + const ComputeBbox& compute_bbox, + const SplitPrimitives& split_primitives, + const AABBTraits&); public: // returns a point which must be on one primitive @@ -573,8 +597,8 @@ public: AABBTraits m_traits; // set of input primitives Primitives m_primitives; - // single root node - Node* m_p_root_node = nullptr; + // tree nodes. first node is the root node + std::vector m_nodes; #ifdef CGAL_HAS_THREADS mutable CGAL_MUTEX build_mutex; // mutex used to protect const calls inducing build() and build_kd_tree() #endif @@ -594,7 +618,13 @@ public: #endif const_cast< AABB_tree* >(this)->build(); } - return m_p_root_node; + return std::addressof(m_nodes[0]); + } + + Node& new_node() + { + m_nodes.emplace_back(); + return m_nodes.back(); } private: const Primitive& singleton_data() const { @@ -603,7 +633,7 @@ public: } // search KD-tree - const Search_tree* m_p_search_tree = nullptr; + mutable std::unique_ptr m_p_search_tree; bool m_use_default_search_tree = true; // indicates whether the internal kd-tree should be built #ifdef CGAL_HAS_THREADS std::atomic m_atomic_need_build; @@ -613,11 +643,6 @@ public: mutable bool m_search_tree_constructed = false; #endif - private: - // Disabled copy constructor & assignment operator - typedef AABB_tree Self; - AABB_tree(const Self& src); - Self& operator=(const Self& src); }; // end class AABB_tree @@ -632,6 +657,30 @@ public: #endif {} + template + typename AABB_tree::Self& AABB_tree::operator=(Self&& tree) noexcept + { + m_traits = std::move(tree.m_traits); + m_primitives = std::move(tree.m_primitives); + m_nodes = std::move(tree.m_nodes); + m_p_search_tree = std::move(tree.m_p_search_tree); + m_use_default_search_tree = std::exchange(tree.m_use_default_search_tree, true); +#ifdef CGAL_HAS_THREADS + m_atomic_need_build = tree.m_atomic_need_build.load(std::memory_order_relaxed); + m_atomic_search_tree_constructed = tree.m_atomic_search_tree_constructed.load(std::memory_order_relaxed); +#else + m_need_build = std::exchange(tree.m_need_build, false); + m_search_tree_constructed = std::exchange(tree.m_search_tree_constructed, false); +#endif + return *this; + } + + template + AABB_tree::AABB_tree(Self&& tree) noexcept + { + *this = std::move(tree); + } + template template AABB_tree::AABB_tree(ConstPrimitiveIterator first, @@ -704,6 +753,41 @@ public: #endif } + template + template + void + AABB_tree::expand(Node& node, + ConstPrimitiveIterator first, + ConstPrimitiveIterator beyond, + const std::size_t range, + const ComputeBbox& compute_bbox, + const SplitPrimitives& split_primitives, + const Tr& traits) + { + node.set_bbox(compute_bbox(first, beyond)); + + // sort primitives along longest axis aabb + split_primitives(first, beyond, node.bbox()); + + switch(range) + { + case 2: + node.set_children(*first, *(first+1)); + break; + case 3: + node.set_children(*first, new_node()); + expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives, traits); + break; + default: + const std::size_t new_range = range/2; + node.set_children(new_node(), new_node()); + expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives, traits); + expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives, traits); + } + } + + + // Build the data structure, after calls to insert(..) template void AABB_tree::build() { @@ -719,24 +803,19 @@ public: const SplitPrimitives& split_primitives) { clear_nodes(); + if(m_primitives.size() > 1) { // allocates tree nodes - m_p_root_node = new Node[m_primitives.size()-1](); - if(m_p_root_node == nullptr) - { - std::cerr << "Unable to allocate memory for AABB tree" << std::endl; - CGAL_assertion(m_p_root_node != nullptr); - m_primitives.clear(); - clear(); - } + m_nodes.reserve(m_primitives.size()-1); // constructs the tree - m_p_root_node->expand(m_primitives.begin(), m_primitives.end(), - m_primitives.size(), - compute_bbox, - split_primitives, - m_traits); + expand(new_node(), + m_primitives.begin(), m_primitives.end(), + m_primitives.size(), + compute_bbox, + split_primitives, + m_traits); } #ifdef CGAL_HAS_THREADS m_atomic_need_build.store(false, std::memory_order_release); // in case build() is triggered by a call to root_node() @@ -768,22 +847,13 @@ public: ConstPointIterator beyond) { clear_search_tree(); - m_p_search_tree = new Search_tree(first, beyond); - - if(m_p_search_tree != nullptr) - { + m_p_search_tree = std::make_unique(first, beyond); #ifdef CGAL_HAS_THREADS m_atomic_search_tree_constructed.store(true, std::memory_order_release); // in case build_kd_tree() is triggered by a call to best_hint() #else m_search_tree_constructed = true; #endif return true; - } - else - { - std::cerr << "Unable to allocate memory for accelerating distance queries" << std::endl; - return false; - } } template @@ -793,7 +863,6 @@ public: m_use_default_search_tree = false; } - // constructs the search KD tree from internal primitives template bool AABB_tree::accelerate_distance_queries() diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h index 6fcfef9ede8..d8edaa91d35 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_node.h @@ -32,6 +32,9 @@ namespace CGAL { template class AABB_node { +private: + typedef AABB_node Self; + public: typedef typename AABBTraits::Bounding_box Bounding_box; @@ -41,29 +44,15 @@ public: , m_p_left_child(nullptr) , m_p_right_child(nullptr) { }; - /// Non virtual Destructor - /// Do not delete children because the tree hosts and delete them - ~AABB_node() { }; + AABB_node(Self&& node) = default; + + // Disabled copy constructor & assignment operator + AABB_node(const Self& src) = delete; + Self& operator=(const Self& src) = delete; /// Returns the bounding box of the node const Bounding_box& bbox() const { return m_bbox; } - /** - * @brief Builds the tree by recursive expansion. - * @param first the first primitive to insert - * @param last the last primitive to insert - * @param range the number of primitive of the range - * - * [first,last[ is the range of primitives to be added to the tree. - */ - template - void expand(ConstPrimitiveIterator first, - ConstPrimitiveIterator beyond, - const std::size_t range, - const ComputeBbox& compute_bbox, - const SplitPrimitives& split_primitives, - const AABBTraits&); - /** * @brief General traversal query * @param query the query @@ -95,8 +84,17 @@ public: { return *static_cast(m_p_left_child); } const Primitive& right_data() const { return *static_cast(m_p_right_child); } + template + void set_children(Left& l, Right& r) + { + m_p_left_child = static_cast(std::addressof(l)); + m_p_right_child = static_cast(std::addressof(r)); + } + void set_bbox(const Bounding_box& bbox) + { + m_bbox = bbox; + } -private: Node& left_child() { return *static_cast(m_p_left_child); } Node& right_child() { return *static_cast(m_p_right_child); } Primitive& left_data() { return *static_cast(m_p_left_child); } @@ -111,49 +109,8 @@ private: void *m_p_left_child; void *m_p_right_child; -private: - // Disabled copy constructor & assignment operator - typedef AABB_node Self; - AABB_node(const Self& src); - Self& operator=(const Self& src); - }; // end class AABB_node -template -template -void -AABB_node::expand(ConstPrimitiveIterator first, - ConstPrimitiveIterator beyond, - const std::size_t range, - const ComputeBbox& compute_bbox, - const SplitPrimitives& split_primitives, - const Tr& traits) -{ - m_bbox = compute_bbox(first, beyond); - - // sort primitives along longest axis aabb - split_primitives(first, beyond, m_bbox); - - switch(range) - { - case 2: - m_p_left_child = &(*first); - m_p_right_child = &(*(++first)); - break; - case 3: - m_p_left_child = &(*first); - m_p_right_child = static_cast(this)+1; - right_child().expand(first+1, beyond, 2, compute_bbox, split_primitives, traits); - break; - default: - const std::size_t new_range = range/2; - m_p_left_child = static_cast(this) + 1; - m_p_right_child = static_cast(this) + new_range; - left_child().expand(first, first + new_range, new_range, compute_bbox, split_primitives, traits); - right_child().expand(first + new_range, beyond, range - new_range, compute_bbox, split_primitives, traits); - } -} - template template diff --git a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_search_tree.h b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_search_tree.h index 96f08168671..9ba3cf2481b 100644 --- a/AABB_tree/include/CGAL/internal/AABB_tree/AABB_search_tree.h +++ b/AABB_tree/include/CGAL/internal/AABB_tree/AABB_search_tree.h @@ -83,7 +83,7 @@ namespace CGAL typedef typename CGAL::Orthogonal_k_neighbor_search Neighbor_search; typedef typename Neighbor_search::Tree Tree; private: - Tree* m_p_tree; + Tree m_tree; Point_and_primitive_id get_p_and_p(const Point_and_primitive_id& p) @@ -98,30 +98,22 @@ namespace CGAL public: template AABB_search_tree(ConstPointIterator begin, ConstPointIterator beyond) - : m_p_tree(nullptr) + : m_tree{} { - typedef typename Add_decorated_point::Point_3 Decorated_point; + typedef typename Add_decorated_point::Point_3 Decorated_point; std::vector points; while(begin != beyond) { Point_and_primitive_id pp = get_p_and_p(*begin); - points.push_back(Decorated_point(pp.first,pp.second)); + points.emplace_back(pp.first, pp.second); ++begin; } - m_p_tree = new Tree(points.begin(), points.end()); - if(m_p_tree != nullptr) - m_p_tree->build(); - else - std::cerr << "unable to build the search tree!" << std::endl; + m_tree.insert(points.begin(), points.end()); + m_tree.build(); } - ~AABB_search_tree() { - delete m_p_tree; - } - - Point_and_primitive_id closest_point(const Point& query) const { - Neighbor_search search(*m_p_tree, query, 1); + Neighbor_search search(m_tree, query, 1); return Point_and_primitive_id(static_cast(search.begin()->first), search.begin()->first.id()); } }; diff --git a/AABB_tree/test/AABB_tree/CMakeLists.txt b/AABB_tree/test/AABB_tree/CMakeLists.txt index 997be1089d0..47c63198ba2 100644 --- a/AABB_tree/test/AABB_tree/CMakeLists.txt +++ b/AABB_tree/test/AABB_tree/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( AABB_tree_Tests ) +project(AABB_tree_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - include( ${CGAL_USE_FILE} ) # Kept to test the old behaviour. - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include(${CGAL_USE_FILE}) # Kept to test the old behaviour. +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp b/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp new file mode 100644 index 00000000000..bd2ccdabb80 --- /dev/null +++ b/AABB_tree/test/AABB_tree/aabb_test_move_constructor.cpp @@ -0,0 +1,207 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +class TestCase +{ +}; + +// test 0 is from "aabb_test_singleton_tree" +template <> +class TestCase<0> +{ + typedef CGAL::Simple_cartesian K; + typedef K::FT FT; + typedef K::Point_3 Point; + typedef K::Plane_3 Plane; + typedef K::Segment_3 Segment; + typedef K::Triangle_3 Triangle; + typedef std::vector::iterator Iterator; + typedef CGAL::AABB_segment_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + +public: + Tree create_tree() + { + return Tree(segments.begin(), segments.end()); + } + + void init_tree(Tree&) {} + + bool test_tree(Tree& tree) + { + Plane plane_query(a, b, d); + Triangle triangle_query(a, b, c); + + // Test calls to all functions + CGAL::Emptyset_iterator devnull; + tree.all_intersections(triangle_query, devnull); + tree.all_intersected_primitives(triangle_query, devnull); + assert(tree.any_intersected_primitive(triangle_query)); + assert(tree.any_intersection(triangle_query)); + const CGAL::Bbox_3 bbox = tree.bbox(); + assert(bbox == CGAL::Bbox_3(0, 0, 0, 2, 2, 2)); + tree.clear(); + tree.insert(segments.begin(), segments.end()); + tree.build(); + assert(tree.closest_point(Point(-0.1, -0.1, -0.1)) == Point(0, 0, 0)); + assert(tree.closest_point(Point(-0.1, -0.1, -0.1), Point(0, 0, 0)) == + Point(0, 0, 0)); + assert(tree.closest_point_and_primitive(Point(-0.1, -0.1, -0.1)).second == + segments.begin()); + assert(tree.do_intersect(plane_query) == true); + assert(tree.do_intersect(triangle_query) == true); + assert(!tree.empty()); + assert(tree.size() == 1); + tree.clear(); + assert(tree.size() == 0); + tree.insert(segments.begin(), segments.end()); + assert(tree.size() == 1); + assert(tree.number_of_intersected_primitives(plane_query) == 1); + tree.rebuild(segments.begin(), segments.end()); + assert(tree.size() == 1); + assert(tree.number_of_intersected_primitives(triangle_query) == 1); + assert(tree.squared_distance(Point(0, 0, 0)) == 0); + return true; + } + +private: + Point a = {1.0, 0.0, 0.0}; + Point b = {0.0, 1.0, 0.0}; + Point c = {0.0, 0.0, 1.0}; + Point d = {0.0, 0.0, 0.0}; + std::vector segments = {Segment(Point(0, 0, 0), Point(2, 2, 2))}; +}; + +// test 1 is from "aabb_test_all_intersected_primitives" +template <> +class TestCase<1> +{ + typedef CGAL::Epick K; + typedef K::FT FT; + typedef K::Point_3 Point; + typedef K::Vector_3 Vector; + typedef K::Segment_3 Segment; + typedef K::Ray_3 Ray; + typedef CGAL::Surface_mesh> Mesh; + typedef CGAL::AABB_halfedge_graph_segment_primitive + S_Primitive; + typedef CGAL::AABB_face_graph_triangle_primitive + T_Primitive; + typedef CGAL::AABB_traits T_Traits; + typedef CGAL::AABB_traits S_Traits; + typedef CGAL::AABB_tree T_Tree; + typedef CGAL::AABB_tree S_Tree; + typedef T_Tree::Primitive_id T_Primitive_id; + typedef S_Tree::Primitive_id S_Primitive_id; + typedef std::pair TreePair; + +public: + TreePair create_tree() + { + static CGAL::Surface_mesh> m1 = {}; + static CGAL::Surface_mesh> m2 = {}; + static bool mesh_loaded = false; + if (!mesh_loaded) { + std::ifstream in("data/cube.off"); + assert(in); + in >> m1; + in.close(); + in.open("data/tetrahedron.off"); + assert(in); + in >> m2; + in.close(); + mesh_loaded = true; + } + return std::make_pair(T_Tree{faces(m1).first, faces(m1).second, m1}, + S_Tree{edges(m2).first, edges(m2).second, m2}); + } + + void init_tree(TreePair& trees) + { + trees.first.build(); + trees.second.build(); + } + + bool test_tree(TreePair& trees) + { + auto &cube_tree = trees.first; + auto &tet_tree = trees.second; + + std::list t_primitives; + std::list s_primitives; + cube_tree.all_intersected_primitives(tet_tree, + std::back_inserter(t_primitives)); + CGAL_assertion(t_primitives.size() == 6); + tet_tree.all_intersected_primitives(cube_tree, + std::back_inserter(s_primitives)); + CGAL_assertion(s_primitives.size() == 6); + CGAL_assertion(tet_tree.do_intersect(cube_tree)); + CGAL_assertion(cube_tree.do_intersect(tet_tree)); + + std::vector all_primitives; + cube_tree.all_intersected_primitives(tet_tree, + std::back_inserter(all_primitives)); + bool found_f5 = false; + for (auto prim : all_primitives) { + if ((int)prim.first == 5) + found_f5 = true; + } + CGAL_assertion(found_f5); + CGAL_USE(found_f5); + return true; + } +}; + + +template +bool run_test() +{ + TestCase test_case; + + // create_tree should return prvalue for guaranteed copy elision + auto tree_1 = test_case.create_tree(); + test_case.init_tree(tree_1); + + auto tree_2 = test_case.create_tree(); + test_case.init_tree(tree_2); + + auto tree_3 = test_case.create_tree(); + test_case.init_tree(tree_3); + + decltype(tree_1) tree_ctor{std::move(tree_2)}; + decltype(tree_1) tree_assig{}; + tree_assig = std::move(tree_3); + + bool normal = test_case.test_tree(tree_1); + bool move_ctor = test_case.test_tree(tree_ctor); + bool move_ass = + test_case.test_tree(tree_assig); // test move assignment operator + + if (!normal) + std::cout << "Test " << test_number << "failed on the original tree\n"; + if (!move_ctor) + std::cout << "Test " << test_number << "failed on move constructed tree\n"; + if (!move_ass) + std::cout << "Test " << test_number << "failed on move assigned tree\n"; + return normal && move_ctor && move_ass; +} + +int main() { return (run_test<0>() && run_test<1>()) ? 0 : 1; } diff --git a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/CMakeLists.txt b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/CMakeLists.txt index e62cfe0689a..d494c037fae 100644 --- a/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/CMakeLists.txt +++ b/Advancing_front_surface_reconstruction/examples/Advancing_front_surface_reconstruction/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Advancing_front_surface_reconstruction_Examples ) +project(Advancing_front_surface_reconstruction_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Advancing_front_surface_reconstruction/test/Advancing_front_surface_reconstruction/CMakeLists.txt b/Advancing_front_surface_reconstruction/test/Advancing_front_surface_reconstruction/CMakeLists.txt index 07b424ed360..c16decef5c2 100644 --- a/Advancing_front_surface_reconstruction/test/Advancing_front_surface_reconstruction/CMakeLists.txt +++ b/Advancing_front_surface_reconstruction/test/Advancing_front_surface_reconstruction/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Advancing_front_surface_reconstruction_Tests ) +project(Advancing_front_surface_reconstruction_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Algebraic_foundations/examples/Algebraic_foundations/CMakeLists.txt b/Algebraic_foundations/examples/Algebraic_foundations/CMakeLists.txt index c616d6befdc..b86aa4c60bc 100644 --- a/Algebraic_foundations/examples/Algebraic_foundations/CMakeLists.txt +++ b/Algebraic_foundations/examples/Algebraic_foundations/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_foundations_Examples ) +project(Algebraic_foundations_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Algebraic_foundations/test/Algebraic_foundations/CMakeLists.txt b/Algebraic_foundations/test/Algebraic_foundations/CMakeLists.txt index 682fa668f93..a2286014e09 100644 --- a/Algebraic_foundations/test/Algebraic_foundations/CMakeLists.txt +++ b/Algebraic_foundations/test/Algebraic_foundations/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_foundations_Tests ) +project(Algebraic_foundations_Tests) +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core) - -if ( CGAL_FOUND ) - - include(${CGAL_USE_FILE}) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include(${CGAL_USE_FILE}) +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Algebraic_kernel_d/examples/Algebraic_kernel_d/CMakeLists.txt b/Algebraic_kernel_d/examples/Algebraic_kernel_d/CMakeLists.txt index 02f1ac1c563..63cf6965333 100644 --- a/Algebraic_kernel_d/examples/Algebraic_kernel_d/CMakeLists.txt +++ b/Algebraic_kernel_d/examples/Algebraic_kernel_d/CMakeLists.txt @@ -1,28 +1,27 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_kernel_d_Examples ) +project(Algebraic_kernel_d_Examples) +find_package(CGAL REQUIRED COMPONENTS Core) +find_package(MPFI QUIET) -find_package(CGAL QUIET COMPONENTS Core) +if(MPFI_FOUND) -if ( CGAL_FOUND ) - find_package(MPFI QUIET) -endif() + include(${CGAL_USE_FILE}) + include(${MPFI_USE_FILE}) + include(CGAL_VersionUtils) -if( CGAL_FOUND AND MPFI_FOUND) - - include( ${CGAL_USE_FILE} ) - include( ${MPFI_USE_FILE} ) - include( CGAL_VersionUtils ) - - create_single_source_cgal_program( "Compare_1.cpp" ) - create_single_source_cgal_program( "Construct_algebraic_real_1.cpp" ) - create_single_source_cgal_program( "Isolate_1.cpp" ) - create_single_source_cgal_program( "Sign_at_1.cpp" ) - create_single_source_cgal_program( "Solve_1.cpp" ) + create_single_source_cgal_program("Compare_1.cpp") + create_single_source_cgal_program("Construct_algebraic_real_1.cpp") + create_single_source_cgal_program("Isolate_1.cpp") + create_single_source_cgal_program("Sign_at_1.cpp") + create_single_source_cgal_program("Solve_1.cpp") else() - message(STATUS "This program requires the CGAL library and MPFI, and will not be compiled.") + message( + STATUS + "This program requires the CGAL library and MPFI, and will not be compiled." + ) endif() diff --git a/Algebraic_kernel_d/test/Algebraic_kernel_d/CMakeLists.txt b/Algebraic_kernel_d/test/Algebraic_kernel_d/CMakeLists.txt index 73b7294442b..b48f6a7e334 100644 --- a/Algebraic_kernel_d/test/Algebraic_kernel_d/CMakeLists.txt +++ b/Algebraic_kernel_d/test/Algebraic_kernel_d/CMakeLists.txt @@ -1,67 +1,65 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_kernel_d_Tests ) - - +project(Algebraic_kernel_d_Tests) # CGAL and its components -find_package( CGAL QUIET COMPONENTS Core) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() +find_package(CGAL REQUIRED COMPONENTS Core) find_package(RS3 QUIET) if(MPFI_FOUND) - include( ${MPFI_USE_FILE} ) + include(${MPFI_USE_FILE}) endif() if(RS3_FOUND) - include( ${RS3_USE_FILE} ) + include(${RS3_USE_FILE}) endif() # Boost and its components -find_package( Boost ) +find_package(Boost) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() endif() # include for local directory -include_directories( BEFORE include ) +include_directories(BEFORE include) -include( ${CGAL_USE_FILE} ) +include(${CGAL_USE_FILE}) # Creating entries for all .cpp/.C files with "main" routine # ########################################################## -create_single_source_cgal_program( "cyclic.cpp" ) -create_single_source_cgal_program( "Algebraic_curve_kernel_2.cpp" ) -create_single_source_cgal_program( "algebraic_curve_kernel_2_tools.cpp" ) -create_single_source_cgal_program( "Algebraic_kernel_d_1_LEDA.cpp" ) +create_single_source_cgal_program("cyclic.cpp") +create_single_source_cgal_program("Algebraic_curve_kernel_2.cpp") +create_single_source_cgal_program("algebraic_curve_kernel_2_tools.cpp") +create_single_source_cgal_program("Algebraic_kernel_d_1_LEDA.cpp") -create_single_source_cgal_program( "Algebraic_kernel_d_1_CORE_Integer_rational.cpp" ) -create_single_source_cgal_program( "Algebraic_kernel_d_1_CORE_SqrtII_rational.cpp" ) -create_single_source_cgal_program( "Algebraic_kernel_d_1_CORE_SqrtRI_rational.cpp" ) -create_single_source_cgal_program( "Algebraic_kernel_d_1_CORE_SqrtRR_rational.cpp" ) +create_single_source_cgal_program( + "Algebraic_kernel_d_1_CORE_Integer_rational.cpp") +create_single_source_cgal_program( + "Algebraic_kernel_d_1_CORE_SqrtII_rational.cpp") +create_single_source_cgal_program( + "Algebraic_kernel_d_1_CORE_SqrtRI_rational.cpp") +create_single_source_cgal_program( + "Algebraic_kernel_d_1_CORE_SqrtRR_rational.cpp") -create_single_source_cgal_program( "Algebraic_kernel_d_1_GMP.cpp" ) -create_single_source_cgal_program( "Algebraic_kernel_d_2.cpp" ) -create_single_source_cgal_program( "Algebraic_real_d_1.cpp" ) -create_single_source_cgal_program( "Bitstream_descartes.cpp" ) -create_single_source_cgal_program( "Curve_analysis_2.cpp" ) -create_single_source_cgal_program( "Curve_pair_analysis_2.cpp" ) -create_single_source_cgal_program( "Descartes.cpp" ) -create_single_source_cgal_program( "Real_embeddable_traits_extension.cpp" ) +create_single_source_cgal_program("Algebraic_kernel_d_1_GMP.cpp") +create_single_source_cgal_program("Algebraic_kernel_d_2.cpp") +create_single_source_cgal_program("Algebraic_real_d_1.cpp") +create_single_source_cgal_program("Bitstream_descartes.cpp") +create_single_source_cgal_program("Curve_analysis_2.cpp") +create_single_source_cgal_program("Curve_pair_analysis_2.cpp") +create_single_source_cgal_program("Descartes.cpp") +create_single_source_cgal_program("Real_embeddable_traits_extension.cpp") if(RS_FOUND) - create_single_source_cgal_program( "Algebraic_kernel_rs_gmpq_d_1.cpp" ) - create_single_source_cgal_program( "Algebraic_kernel_rs_gmpz_d_1.cpp" ) + create_single_source_cgal_program("Algebraic_kernel_rs_gmpq_d_1.cpp") + create_single_source_cgal_program("Algebraic_kernel_rs_gmpz_d_1.cpp") else() - message(STATUS "NOTICE: Some tests require the RS library, and will not be compiled.") + message( + STATUS + "NOTICE: Some tests require the RS library, and will not be compiled.") endif() diff --git a/Algebraic_kernel_for_circles/test/Algebraic_kernel_for_circles/CMakeLists.txt b/Algebraic_kernel_for_circles/test/Algebraic_kernel_for_circles/CMakeLists.txt index c02ce4ff14d..006778479a8 100644 --- a/Algebraic_kernel_for_circles/test/Algebraic_kernel_for_circles/CMakeLists.txt +++ b/Algebraic_kernel_for_circles/test/Algebraic_kernel_for_circles/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_kernel_for_circles_Tests ) +project(Algebraic_kernel_for_circles_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - include_directories (BEFORE "include") - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include_directories(BEFORE "include") +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Algebraic_kernel_for_spheres/test/Algebraic_kernel_for_spheres/CMakeLists.txt b/Algebraic_kernel_for_spheres/test/Algebraic_kernel_for_spheres/CMakeLists.txt index 284554d7787..48dbc34d1d6 100644 --- a/Algebraic_kernel_for_spheres/test/Algebraic_kernel_for_spheres/CMakeLists.txt +++ b/Algebraic_kernel_for_spheres/test/Algebraic_kernel_for_spheres/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Algebraic_kernel_for_spheres_Tests ) +project(Algebraic_kernel_for_spheres_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - include_directories (BEFORE "include") - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include_directories(BEFORE "include") +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Alpha_shapes_2/examples/Alpha_shapes_2/CMakeLists.txt b/Alpha_shapes_2/examples/Alpha_shapes_2/CMakeLists.txt index 318bbe1dcc3..aa0182a2fc3 100644 --- a/Alpha_shapes_2/examples/Alpha_shapes_2/CMakeLists.txt +++ b/Alpha_shapes_2/examples/Alpha_shapes_2/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Alpha_shapes_2_Examples ) +project(Alpha_shapes_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Alpha_shapes_2/test/Alpha_shapes_2/CMakeLists.txt b/Alpha_shapes_2/test/Alpha_shapes_2/CMakeLists.txt index 5b6cea7e446..a14ae249da7 100644 --- a/Alpha_shapes_2/test/Alpha_shapes_2/CMakeLists.txt +++ b/Alpha_shapes_2/test/Alpha_shapes_2/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Alpha_shapes_2_Tests ) +project(Alpha_shapes_2_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Alpha_shapes_3/demo/Alpha_shapes_3/CMakeLists.txt b/Alpha_shapes_3/demo/Alpha_shapes_3/CMakeLists.txt index 15a15504881..ede9b5e1367 100644 --- a/Alpha_shapes_3/demo/Alpha_shapes_3/CMakeLists.txt +++ b/Alpha_shapes_3/demo/Alpha_shapes_3/CMakeLists.txt @@ -2,7 +2,7 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.15) -project (Alpha_shapes_3_Demo) +project(Alpha_shapes_3_Demo) # Find includes in corresponding build directories set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -16,35 +16,38 @@ if(POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() -find_package(CGAL COMPONENTS Qt5) +find_package(CGAL REQUIRED OPTIONAL_COMPONENTS Qt5) find_package(Qt5 QUIET COMPONENTS Xml Script OpenGL Svg) -if ( CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND ) +if(CGAL_Qt5_FOUND AND Qt5_FOUND) add_definitions(-DQT_NO_KEYWORDS) - # include(${QT_USE_FILE}) - include_directories (BEFORE ./ ) + # include(${QT_USE_FILE}) + include_directories(BEFORE ./) # ui file, created wih Qt Designer - qt5_wrap_ui( uis MainWindow.ui ) + qt5_wrap_ui(uis MainWindow.ui) # qrc files (resources files, that contain icons, at least) - qt5_add_resources ( CGAL_Qt5_RESOURCE_FILES ./Alpha_shape_3.qrc ) + qt5_add_resources(CGAL_Qt5_RESOURCE_FILES ./Alpha_shape_3.qrc) - add_executable ( Alpha_shape_3 Alpha_shape_3.cpp MainWindow.cpp Viewer.cpp ${uis} ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES}) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS Alpha_shape_3 ) + add_executable( + Alpha_shape_3 Alpha_shape_3.cpp MainWindow.cpp Viewer.cpp ${uis} + ${CGAL_Qt5_RESOURCE_FILES} ${CGAL_Qt5_MOC_FILES}) + add_to_cached_list(CGAL_EXECUTABLE_TARGETS Alpha_shape_3) - target_link_libraries( Alpha_shape_3 PRIVATE - CGAL::CGAL CGAL::CGAL_Qt5 - Qt5::OpenGL Qt5::Gui ) + target_link_libraries(Alpha_shape_3 PRIVATE CGAL::CGAL CGAL::CGAL_Qt5 + Qt5::OpenGL Qt5::Gui) include(${CGAL_MODULES_DIR}/CGAL_add_test.cmake) cgal_add_compilation_test(Alpha_shape_3) else() - message(STATUS "NOTICE: This demo requires CGAL, and Qt5, and will not be compiled.") + message( + STATUS "NOTICE: This demo requires CGAL, and Qt5, and will not be compiled." + ) endif() diff --git a/Alpha_shapes_3/examples/Alpha_shapes_3/CMakeLists.txt b/Alpha_shapes_3/examples/Alpha_shapes_3/CMakeLists.txt index bd91f6c8705..b059a33c683 100644 --- a/Alpha_shapes_3/examples/Alpha_shapes_3/CMakeLists.txt +++ b/Alpha_shapes_3/examples/Alpha_shapes_3/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Alpha_shapes_3_Examples ) +project(Alpha_shapes_3_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Alpha_shapes_3/package_info/Alpha_shapes_3/dependencies b/Alpha_shapes_3/package_info/Alpha_shapes_3/dependencies index d6667a72a3d..6a453cfa1e9 100644 --- a/Alpha_shapes_3/package_info/Alpha_shapes_3/dependencies +++ b/Alpha_shapes_3/package_info/Alpha_shapes_3/dependencies @@ -4,7 +4,6 @@ Arithmetic_kernel Cartesian_kernel Circulator Filtered_kernel -Geomview Hash_map Homogeneous_kernel Installation diff --git a/Alpha_shapes_3/test/Alpha_shapes_3/CMakeLists.txt b/Alpha_shapes_3/test/Alpha_shapes_3/CMakeLists.txt index 98bae1eaab9..31551f22a36 100644 --- a/Alpha_shapes_3/test/Alpha_shapes_3/CMakeLists.txt +++ b/Alpha_shapes_3/test/Alpha_shapes_3/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Alpha_shapes_3_Tests ) +project(Alpha_shapes_3_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - include_directories (BEFORE "include") - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include_directories(BEFORE "include") +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Apollonius_graph_2/examples/Apollonius_graph_2/CMakeLists.txt b/Apollonius_graph_2/examples/Apollonius_graph_2/CMakeLists.txt index 86194af24b3..9486b94e36d 100644 --- a/Apollonius_graph_2/examples/Apollonius_graph_2/CMakeLists.txt +++ b/Apollonius_graph_2/examples/Apollonius_graph_2/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Apollonius_graph_2_Examples ) +project(Apollonius_graph_2_Examples) +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core ) - -if ( CGAL_FOUND ) - - include(${CGAL_USE_FILE}) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include(${CGAL_USE_FILE}) +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Apollonius_graph_2/test/Apollonius_graph_2/CMakeLists.txt b/Apollonius_graph_2/test/Apollonius_graph_2/CMakeLists.txt index 8a0318d270d..f67cd40b98a 100644 --- a/Apollonius_graph_2/test/Apollonius_graph_2/CMakeLists.txt +++ b/Apollonius_graph_2/test/Apollonius_graph_2/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Apollonius_graph_2_Tests ) +project(Apollonius_graph_2_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - include_directories (BEFORE "include") - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include_directories(BEFORE "include") +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Arithmetic_kernel/test/Arithmetic_kernel/CMakeLists.txt b/Arithmetic_kernel/test/Arithmetic_kernel/CMakeLists.txt index 82660d4b397..1568cf2d61c 100644 --- a/Arithmetic_kernel/test/Arithmetic_kernel/CMakeLists.txt +++ b/Arithmetic_kernel/test/Arithmetic_kernel/CMakeLists.txt @@ -1,56 +1,53 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Arithmetic_kernel_Tests ) +project(Arithmetic_kernel_Tests) - - - -find_package(CGAL QUIET COMPONENTS Core) +find_package(CGAL REQUIRED COMPONENTS Core) find_package(GMP QUIET) -if ( CGAL_FOUND AND GMP_FOUND ) +if(GMP_FOUND) include(${CGAL_USE_FILE}) - include( CGAL_VersionUtils ) + include(CGAL_VersionUtils) - get_dependency_version( GMP ) + get_dependency_version(GMP) - IS_VERSION_LESS("${GMP_VERSION}" "4.2.0" _IS_GMP_VERSION_TO_LOW) + is_version_less("${GMP_VERSION}" "4.2.0" _IS_GMP_VERSION_TO_LOW) include_directories(include) - find_package( MPFI ) + find_package(MPFI) - if( MPFI_FOUND ) - include( ${MPFI_USE_FILE} ) + if(MPFI_FOUND) + include(${MPFI_USE_FILE}) # for the testsuite, the version of MPFI shipped with RS is used; this # version needs GMP>=4.2, so we require this dependency only here and # not in FindMPFI.cmake - if( _IS_GMP_VERSION_TO_LOW ) - message( STATUS - "MPFI tests need GMP>=4.2, some of the tests will not be compiled" ) - else( _IS_GMP_VERSION_TO_LOW ) - include( ${MPFI_USE_FILE} ) - create_single_source_cgal_program( "GMP_arithmetic_kernel.cpp" ) - endif( _IS_GMP_VERSION_TO_LOW ) - else( MPFI_FOUND ) - message( STATUS - "MPFI is not present, some of the tests will not be compiled." ) - endif( MPFI_FOUND ) + if(_IS_GMP_VERSION_TO_LOW) + message( + STATUS + "MPFI tests need GMP>=4.2, some of the tests will not be compiled") + else(_IS_GMP_VERSION_TO_LOW) + include(${MPFI_USE_FILE}) + create_single_source_cgal_program("GMP_arithmetic_kernel.cpp") + endif(_IS_GMP_VERSION_TO_LOW) + else(MPFI_FOUND) + message( + STATUS "MPFI is not present, some of the tests will not be compiled.") + endif(MPFI_FOUND) - create_single_source_cgal_program( "Arithmetic_kernel.cpp" ) - create_single_source_cgal_program( "LEDA_arithmetic_kernel.cpp" ) - create_single_source_cgal_program( "CORE_arithmetic_kernel.cpp" ) - create_single_source_cgal_program( "Get_arithmetic_kernel.cpp" ) + create_single_source_cgal_program("Arithmetic_kernel.cpp") + create_single_source_cgal_program("LEDA_arithmetic_kernel.cpp") + create_single_source_cgal_program("CORE_arithmetic_kernel.cpp") + create_single_source_cgal_program("Get_arithmetic_kernel.cpp") else() - message(STATUS "This program requires the CGAL library, and will not be compiled.") + message( + STATUS "This program requires the CGAL library, and will not be compiled.") endif() - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.cpp new file mode 100644 index 00000000000..c25b21c6d43 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial + +#include "AlgebraicCurveInputDialog.h" +#include "ui_AlgebraicCurveInputDialog.h" + +AlgebraicCurveInputDialog::AlgebraicCurveInputDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AlgebraicCurveInputDialog) +{ + ui->setupUi(this); + ui->lineEdit->setFocus(); +} + +AlgebraicCurveInputDialog::~AlgebraicCurveInputDialog() +{ + delete ui; +} + +std::string AlgebraicCurveInputDialog::getLineEditText() +{ + QString lineEditText = ui->lineEdit->text(); + return lineEditText.toStdString(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.h new file mode 100644 index 00000000000..780dc4c6645 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.h @@ -0,0 +1,34 @@ +// Copyright (c) 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial + +#ifndef ALGEBRAICCURVEINPUTDIALOG_H +#define ALGEBRAICCURVEINPUTDIALOG_H + +#include + +namespace Ui +{ +class AlgebraicCurveInputDialog; +} + +class AlgebraicCurveInputDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AlgebraicCurveInputDialog(QWidget *parent = 0); + ~AlgebraicCurveInputDialog(); + std::string getLineEditText(); + Ui::AlgebraicCurveInputDialog* getUi(){return this->ui;} + +private: + Ui::AlgebraicCurveInputDialog *ui; +}; + +#endif // ALGEBRAICCURVEINPUTDIALOG_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.ui b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.ui new file mode 100644 index 00000000000..3450408f205 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveInputDialog.ui @@ -0,0 +1,77 @@ + + + AlgebraicCurveInputDialog + + + + 0 + 0 + 448 + 173 + + + + Dialog + + + + + + + + + 1 + + + <html><head/><body><p align="justify">Enter the polynomial that represents the curve you would like to insert.</p><p align="justify">For example, to insert a circle of radius 10 centered at (10,10) enter:</p><p align="center"><span style=" color:#000000;">(x-10)^2+(y-10)^2=10^2</span></p></body></html> + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AlgebraicCurveInputDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AlgebraicCurveInputDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.cpp new file mode 100644 index 00000000000..19d3405bb9b --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.cpp @@ -0,0 +1,174 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// 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. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// SPDX-License-Identifier: GPL-3.0+ +// +// Author(s): Saurabh Singh +// Ahmed Essam + +#include +#include + +#include +#include + +#include "AlgebraicCurveParser.h" + +namespace phx = boost::phoenix; +namespace qi = boost::spirit::qi; +namespace ascii = boost::spirit::ascii; + +template +struct PolynomialParser : qi::grammar +{ + using Self = PolynomialParser; + using Traits = CGAL::Polynomial_traits_d; + using Coefficient = typename Traits::Innermost_coefficient_type; + using Innermost_leading_coefficient = + typename Traits::Innermost_leading_coefficient; + using Total_degree = typename Traits::Total_degree; + + PolynomialParser() : PolynomialParser::base_type(start) + { + using qi::_val; + using qi::eps; + + for (int i = 0; i < Traits::d; i++) + vars[i] = CGAL::shift(Polynomial_d(1), 1, i); + + // { expr = expr } or { expr } + start = (expr >> '=' >> expr)[_val = qi::_1 - qi::_2] | expr[_val = qi::_1]; + // addition and subtraction + expr = term[_val = qi::_1] >> + *('+' >> term[_val += qi::_1] | '-' >> term[_val -= qi::_1]); + // multiplication using *, and implied multiplication as in (x+y)(x+y) + term = factor[_val = qi::_1] >> + *(('*' >> factor[_val *= qi::_1]) | pow_expr[_val *= qi::_1]); + // uniary - and + operators + factor = qi::char_('-') >> pow_expr[_val = -qi::_1] | + -qi::char_('+') >> pow_expr[_val = qi::_1]; + // power + pow_expr = + factor2[_val = qi::_1] >> + (('^' >> factor2[_val = phx::bind(&Self::raise, this, _val, qi::_1)]) | + eps); + // ( expr ) + factor2 = (('(' >> expr >> ')') | factor3)[_val = qi::_1]; + // coefficients and variables + factor3 = + coeff[_val = phx::construct(qi::_1)] | var[_val = qi::_1]; + coeff = qi::as_string[qi::lexeme[+qi::digit]] + [_val = phx::construct(qi::_1)]; + if (Traits::d == 1) + var = qi::char_('x')[_val = vars[0]]; + else + var = qi::char_('x')[_val = vars[0]] | qi::char_('y')[_val = vars[1]]; + } + + Polynomial_d raise(const Polynomial_d& poly, const Polynomial_d& power) + { + if (total_degree(power) != 0) + { + this->error = true; + return {}; + } + + return CGAL::ipower( + poly, std::lround(CGAL::to_double(innermost_leading_coefficient(power)))); + } + + Innermost_leading_coefficient innermost_leading_coefficient; + Total_degree total_degree; + + Polynomial_d vars[Traits::d]; + + qi::rule start; + qi::rule expr; + qi::rule term; + qi::rule pow_expr; + qi::rule factor; + qi::rule factor2; + qi::rule factor3; + qi::rule var; + qi::rule coeff; + + bool error = false; +}; + +static bool hasValidChars2D(const std::string& expression) +{ + const char valid_chars[] = {'x', 'y', '+', '-', '*', '(', ')', '^', '='}; + return std::all_of(expression.begin(), expression.end(), [&](char c) { + return std::isspace(c) || std::isdigit(c) || + std::find(std::begin(valid_chars), std::end(valid_chars), c) != + std::end(valid_chars); + }); +} + +static bool hasValidChars1D(const std::string& expression) +{ + const char valid_chars[] = {'x', '+', '-', '*', '(', ')', '^'}; + return std::all_of(expression.begin(), expression.end(), [&](char c) { + return std::isspace(c) || std::isdigit(c) || + std::find(std::begin(valid_chars), std::end(valid_chars), c) != + std::end(valid_chars); + }); +} + +static inline bool hasValidChars(const std::string& expression, int dimension) +{ + if (dimension == 1) + return hasValidChars1D(expression); + else + return hasValidChars2D(expression); +} + +template +boost::optional +AlgebraicCurveParser::operator()(const std::string& expression) +{ + using Traits = CGAL::Polynomial_traits_d; + using iterator_type = std::string::const_iterator; + + if (!hasValidChars(expression, Traits::d)) return {}; + + PolynomialParser pparser; + std::string::const_iterator iter = expression.begin(); + std::string::const_iterator end = expression.end(); + + // parsing goes on here + Polynomial_d poly; + bool r = qi::phrase_parse(iter, end, pparser, ascii::space, poly); + + if (r && iter == end && !pparser.error) + return poly; + else + return {}; +} + +#ifdef CGAL_USE_CORE +// don't want to include ArrangementTypes.h +// makes compilation slower +// template class +// AlgebraicCurveParser; +// AlgebraicCurveParser; +#include +#include + +template struct AlgebraicCurveParser< + CGAL::Arr_algebraic_segment_traits_2::Polynomial_2>; + +template struct AlgebraicCurveParser< + typename CGAL::Algebraic_kernel_d_1::Polynomial_1>; +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.h new file mode 100644 index 00000000000..e838f2e3c0d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/AlgebraicCurveParser.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// 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. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// SPDX-License-Identifier: GPL-3.0+ +// +// Author(s): Saurabh Singh +// Ahmed Essam + +#ifndef ARRANGEMENT_ON_SURFACE_2_DEMO_ALGEBRAICCURVEPARSERNEW_H +#define ARRANGEMENT_ON_SURFACE_2_DEMO_ALGEBRAICCURVEPARSERNEW_H + +#include +#include +#include + +template +struct AlgebraicCurveParser +{ + boost::optional operator()(const std::string& expression); +}; + +#endif //ARRANGEMENT_ON_SURFACE_2_DEMO_ALGEBRAICCURVEPARSERNEW_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrTraitsAdaptor.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrTraitsAdaptor.h new file mode 100644 index 00000000000..a248d8378e7 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrTraitsAdaptor.h @@ -0,0 +1,108 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#ifndef CGAL_ARRANGEMENTS_ARR_TRAITS_ADAPTOR_H +#define CGAL_ARRANGEMENTS_ARR_TRAITS_ADAPTOR_H + +#include "ForwardDeclarations.h" + +/** + * Support for new ArrTraits should specify types: + * + * Kernel - a not-necessarily-exact kernel to represent the arrangement + * graphically. We'll use the Point_2 type provided by this kernel for + * computing distances + * Point_2 - the point type used in the particular arrangement + * CoordinateType - the coordinate type used by the point type + */ +template +class ArrTraitsAdaptor +{ +}; + +template +class ArrTraitsAdaptor> +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_segment_traits_2 ArrTraits; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::FT CoordinateType; +}; + +template +class ArrTraitsAdaptor> +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_linear_traits_2 ArrTraits; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::FT CoordinateType; +}; + +template +class ArrTraitsAdaptor> +{ +public: + typedef CGAL::Arr_polyline_traits_2 ArrTraits; + typedef typename SegmentTraits::Kernel Kernel; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::FT CoordinateType; +}; + +template +class ArrTraitsAdaptor> +{ +public: + typedef CGAL::Arr_conic_traits_2 ArrTraits; + typedef AlgKernel Kernel; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::FT CoordinateType; +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class ArrTraitsAdaptor> +{ +public: + typedef CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits> + ArrTraits; + typedef RatKernel Kernel; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::FT CoordinateType; +}; + +template +class ArrTraitsAdaptor> +{ +public: + typedef Coefficient_ Coefficient; + typedef typename CGAL::Arr_algebraic_segment_traits_2 ArrTraits; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename ArrTraits::Algebraic_real_1 CoordinateType; + typedef CGAL::Cartesian Kernel; +}; + +template +class ArrTraitsAdaptor< + CGAL::Arr_rational_function_traits_2> +{ +public: + typedef typename CGAL::Arr_rational_function_traits_2 + ArrTraits; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename ArrTraits::Algebraic_real_1 CoordinateType; + typedef CGAL::Cartesian Kernel; +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementCurveInputCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementCurveInputCallback.h deleted file mode 100644 index a628687f119..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementCurveInputCallback.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef ARRANGEMENT_CURVE_INPUT_CALLBACK_H -#define ARRANGEMENT_CURVE_INPUT_CALLBACK_H - -#include -#include -#include -#include -#include -#include -#include "GraphicsViewCurveInput.h" -#include "Utils.h" - -template -class ArrangementCurveInputCallback: - public CGAL::Qt::GraphicsViewCurveInput< typename Arr_::Geometry_traits_2 > -{ -public: - typedef Arr_ Arrangement; - typedef ArrTraits Traits; - typedef CGAL::Qt::GraphicsViewCurveInput< Traits > Superclass; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename ArrTraitsAdaptor< Traits >::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::FT FT; - - ArrangementCurveInputCallback( Arrangement* arrangement_, QObject* parent ): - Superclass( parent ), - arrangement( arrangement_ ) - { - this->snapToVertexStrategy.setArrangement( arrangement_ ); - - QObject::connect( this, SIGNAL( generate( CGAL::Object ) ), - this, SLOT( processInput( CGAL::Object ) ) ); - } - - void processInput( CGAL::Object o ) - { - Curve_2 curve; - X_monotone_curve_2 xcurve; - if ( CGAL::assign( curve, o ) ) - { - CGAL::insert( *( this->arrangement ), curve ); - } -#if 0 - else if ( CGAL::assign( xcurve, o ) ) - { - std::vector< X_monotone_curve_2 > box; - box.push_back( xcurve ); - CGAL::insert( *( this->arrangement ), box.begin( ), box.end( ) ); - } -#endif - - Q_EMIT CGAL::Qt::GraphicsViewInput::modelChanged( ); - } - - void setScene( QGraphicsScene* scene ) - { - this->Superclass::setScene( scene ); - this->snapToVertexStrategy.setScene( scene ); - this->snapToGridStrategy.setScene( scene ); - } - - void setArrangement( Arrangement* newArr ) - { - this->arrangement = newArr; - } - -protected: - Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - if ( this->snapToGridEnabled ) - { - return this->snapToGridStrategy.snapPoint( event ); - } - else if ( this->snappingEnabled ) - { - return this->snapToVertexStrategy.snapPoint( event ); - } - else - { - Kernel_point_2 p = this->convert( event->scenePos( ) ); - Point_2 res = this->toArrPoint( p ); - return res; - } - } - - Arrangement* arrangement; - SnapToArrangementVertexStrategy< Arrangement > snapToVertexStrategy; - SnapToGridStrategy< typename Arrangement::Geometry_traits_2 > - snapToGridStrategy; - Arr_construct_point_2< Traits > toArrPoint; -}; // class ArrangementCurveInputCallback - -#endif // ARRANGEMENT_SEGMENT_INPUT_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.cpp index cc08513c55b..bc09e4708a5 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,114 +7,49 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementDemoGraphicsView.h" #include +#include #include #include +#include +#include +#include +//! Member function to setup the viewport of the screen +/*! + \param parent a Qwidget pointer to the class +*/ ArrangementDemoGraphicsView::ArrangementDemoGraphicsView( QWidget* parent ) : QGraphicsView( parent ), - showGrid( false ), - gridSize( 50 ), - gridColor( ::Qt::black ), - backgroundColor( ::Qt::white ) + maxScale( 500000 ), + minScale( 0.0002 ) { - QTransform m( 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 ); - this->setTransform( m ); - this->setBackgroundBrush( QBrush( backgroundColor ) ); + this->resetTransform(); + this->setResizeAnchor(QGraphicsView::AnchorUnderMouse); + this->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); + this->setMouseTracking( true ); + this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + // TODO: Make options menu work + this->setRenderHint(QPainter::Antialiasing); } -void ArrangementDemoGraphicsView::setShowGrid( bool b ) +void ArrangementDemoGraphicsView::paintEvent(QPaintEvent* event) { - this->showGrid = b; + qreal scale = std::sqrt(std::abs(this->transform().determinant())); + if (scale > this->maxScale) + this->scale(this->maxScale / scale, this->maxScale / scale); + else if (scale < this->minScale) + this->scale(this->minScale / scale, this->minScale / scale); + QGraphicsView::paintEvent(event); } -bool ArrangementDemoGraphicsView::getShowGrid( ) const +void ArrangementDemoGraphicsView::resetTransform() { - return this->showGrid; -} - -void ArrangementDemoGraphicsView::setGridSize( int size ) -{ - this->gridSize = size; -} - -int ArrangementDemoGraphicsView::getGridSize( ) const -{ - return this->gridSize; -} - -void ArrangementDemoGraphicsView::setGridColor( QColor color ) -{ - this->gridColor = color; -} - -QColor ArrangementDemoGraphicsView::getGridColor( ) const -{ - return this->gridColor; -} - -void ArrangementDemoGraphicsView::setBackgroundColor( QColor color ) -{ - this->backgroundColor = color; -} - -QColor ArrangementDemoGraphicsView::getBackgroundColor( ) const -{ - return this->backgroundColor; -} - -void ArrangementDemoGraphicsView::drawForeground( QPainter* painter, - const QRectF& /* rect */) -{ - QRectF viewportRect = this->getViewportRect( ); - if ( this->showGrid ) - { - // compute integer-spaced grid lines - QVarLengthArray< QLineF, 100 > linesX; - QVarLengthArray< QLineF, 100 > linesY; - qreal left = - int(viewportRect.left()) - (int(viewportRect.left()) % this->gridSize); - qreal top = - int(viewportRect.top()) - (int(viewportRect.top()) % this->gridSize); - for ( qreal x = left; x < viewportRect.right( ); x += this->gridSize ) - { - linesX.append( QLineF(x, viewportRect.top(), x, viewportRect.bottom())); - } - for ( qreal y = top; y < viewportRect.bottom( ); y += this->gridSize ) - { - linesY.append(QLineF(viewportRect.left( ), y, viewportRect.right(), y)); - } - - // set up the painter - QPen savePen = painter->pen( ); - QPen gridPen( savePen ); - gridPen.setColor( this->gridColor ); - painter->setPen( gridPen ); - - // draw the grid - painter->drawLines( linesX.data( ), linesX.size( ) ); - painter->drawLines( linesY.data( ), linesY.size( ) ); - - // revert the painter - painter->setPen( savePen ); - } -} - -QRectF ArrangementDemoGraphicsView::getViewportRect( ) const -{ - QPointF p1 = this->mapToScene( 0, 0 ); - QPointF p2 = this->mapToScene( this->width( ), this->height( ) ); - - double xmin = (std::min)( p1.x( ), p2.x( ) ); - double xmax = (std::max)( p1.x( ), p2.x( ) ); - double ymin = (std::min)( p1.y( ), p2.y( ) ); - double ymax = (std::max)( p1.y( ), p2.y( ) ); - - QRectF res = QRectF( QPointF( xmin, ymin ), QPointF( xmax, ymax ) ); - - return res; + this->setTransform({1.0, 0.0, 0.0, -1.0, 0.0, 0.0}); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.h index 2979c911054..f0ec2b3ac1f 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoGraphicsView.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef ARRANGEMENT_DEMO_GRAPHICS_VIEW_H #define ARRANGEMENT_DEMO_GRAPHICS_VIEW_H @@ -15,29 +16,22 @@ #include #include +class QPaintEvent; + class ArrangementDemoGraphicsView : public QGraphicsView { public: ArrangementDemoGraphicsView( QWidget* parent = 0 ); - void setShowGrid( bool b ); - bool getShowGrid( ) const; - void setGridSize( int size ); - int getGridSize( ) const; - void setGridColor( QColor color ); - QColor getGridColor( ) const; void setBackgroundColor( QColor color ); QColor getBackgroundColor( ) const; - + void resetTransform(); protected: - void drawForeground( QPainter* painter, const QRectF& rect ); - QRectF getViewportRect( ) const; + void paintEvent(QPaintEvent* event) override; - bool showGrid; - int gridSize; - QColor gridColor; - QColor backgroundColor; + qreal maxScale; + qreal minScale; }; #endif // ARRANGEMENT_DEMO_GRAPHICS_VIEW_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.cpp index d0d4ebf0538..271ceddc01c 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,19 +7,24 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementDemoPropertiesDialog.h" #include "ui_ArrangementDemoPropertiesDialog.h" #include "ArrangementDemoWindow.h" #include "PropertyValueDelegate.h" -#include "DeleteCurveMode.h" #include "ArrangementDemoGraphicsView.h" +#include "VerticalRayShootCallback.h" +#include "ArrangementGraphicsItem.h" +#include "ArrangementDemoTab.h" +#include "EnvelopeCallback.h" +#include "GridGraphicsItem.h" + ArrangementDemoPropertiesDialog:: -ArrangementDemoPropertiesDialog( ArrangementDemoWindow* parent_, - Qt::WindowFlags f ) : - QDialog( parent_, f ), +ArrangementDemoPropertiesDialog( ArrangementDemoWindow* parent_ ) : + QDialog( parent_ ), parent( parent_ ), ui( new Ui::ArrangementDemoPropertiesDialog ) { @@ -43,30 +48,14 @@ QVariant ArrangementDemoPropertiesDialog::property( int index ) // return user data, if it is set QVariant myData = item->data( Qt::UserRole ); - /* - if ( qVariantCanConvert< QColor >( myData ) || - qVariantCanConvert< DeleteCurveMode >( myData ) ) - { - return myData; - } - else - { - res = item->data( Qt::DisplayRole ); - } - */ + res = item->data( Qt::DisplayRole ); - if ( myData.canConvert() || - myData.canConvert()) - { - return myData; - } - else - { - res = item->data( Qt::DisplayRole ); - } return res; } +//! function to setup the user interface that contains the buttons to draw and manipulate like segments and cones +/*! +*/ void ArrangementDemoPropertiesDialog::setupUi( ) { this->ui->setupUi( this ); @@ -84,8 +73,6 @@ void ArrangementDemoPropertiesDialog::setupUi( ) QTableWidgetItem* envelopeVertexRadiusItem = new QTableWidgetItem; QTableWidgetItem* verticalRayEdgeColorItem = new QTableWidgetItem; QTableWidgetItem* verticalRayEdgeWidthItem = new QTableWidgetItem; - QTableWidgetItem* deleteCurveModeItem = new QTableWidgetItem; - QTableWidgetItem* gridSizeItem = new QTableWidgetItem; QTableWidgetItem* gridColorItem = new QTableWidgetItem; this->ui->tableWidget->setItem( int(EDGE_COLOR_KEY), 0, edgeColorItem ); @@ -93,33 +80,33 @@ void ArrangementDemoPropertiesDialog::setupUi( ) this->ui->tableWidget->setItem( int(EDGE_WIDTH_KEY), 0, edgeWidthItem ); this->ui->tableWidget->setItem( int(VERTEX_RADIUS_KEY), 0, vertexRadiusItem ); this->ui->tableWidget->setItem( int(ENVELOPE_EDGE_COLOR_KEY), 0, - envelopeEdgeColorItem ); + envelopeEdgeColorItem ); this->ui->tableWidget->setItem( int(ENVELOPE_VERTEX_COLOR_KEY), 0, - envelopeVertexColorItem ); + envelopeVertexColorItem ); this->ui->tableWidget->setItem( int(ENVELOPE_EDGE_WIDTH_KEY), 0, - envelopeEdgeWidthItem ); + envelopeEdgeWidthItem ); this->ui->tableWidget->setItem( int(ENVELOPE_VERTEX_RADIUS_KEY), 0, - envelopeVertexRadiusItem ); + envelopeVertexRadiusItem ); this->ui->tableWidget->setItem( int(VERTICAL_RAY_EDGE_COLOR_KEY), 0, - verticalRayEdgeColorItem ); + verticalRayEdgeColorItem ); this->ui->tableWidget->setItem( int(VERTICAL_RAY_EDGE_WIDTH_KEY), 0, - verticalRayEdgeWidthItem ); - this->ui->tableWidget->setItem( int(DELETE_CURVE_MODE_KEY), 0, - deleteCurveModeItem ); - this->ui->tableWidget->setItem( int(GRID_SIZE_KEY), 0, gridSizeItem ); + verticalRayEdgeWidthItem ); this->ui->tableWidget->setItem( int(GRID_COLOR_KEY), 0, gridColorItem ); // fill in the items with data this->updateUi( ); } +//! Adding a new tab whenever the user creates a new file and updating the menu options accordingly +/*! +*/ void ArrangementDemoPropertiesDialog::updateUi( ) { if ( this->parent == NULL ) { return; } - ArrangementDemoTabBase* currentTab = this->parent->getCurrentTab( ); + ArrangementDemoTab* currentTab = this->parent->getCurrentTab(); if ( currentTab == NULL ) { return; @@ -130,10 +117,10 @@ void ArrangementDemoPropertiesDialog::updateUi( ) return; } - ArrangementDemoGraphicsView* view = currentTab->getView( ); EnvelopeCallbackBase* envelopeCallback = currentTab->getEnvelopeCallback( ); VerticalRayShootCallbackBase* verticalRayShootCallback = - currentTab->getVerticalRayShootCallback( ); + currentTab->getVerticalRayShootCallback( ); + GridGraphicsItem* gridGraphicsItem = currentTab->getGridGraphicsItem(); QPen vertexPen = agi->getVerticesPen( ); QPen edgePen = agi->getEdgesPen( ); @@ -143,42 +130,37 @@ void ArrangementDemoPropertiesDialog::updateUi( ) QColor edgeColor = edgePenBrush.color( ); unsigned int edgeWidth = edgePen.width( ); unsigned int vertexRadius = vertexPen.width( ); - unsigned int gridSize = view->getGridSize( ); - QColor gridColor = view->getGridColor( ); + QColor gridColor = gridGraphicsItem->getAxesColor( ); unsigned int envelopeEdgeWidth = envelopeCallback->getEnvelopeEdgeWidth( ); unsigned int envelopeVertexRadius = - envelopeCallback->getEnvelopeVertexRadius( ); + envelopeCallback->getEnvelopeVertexRadius( ); QColor envelopeEdgeColor = envelopeCallback->getEnvelopeEdgeColor( ); QColor envelopeVertexColor = envelopeCallback->getEnvelopeVertexColor( ); unsigned int verticalRayEdgeWidth = verticalRayShootCallback->edgeWidth( ); QColor verticalRayEdgeColor = verticalRayShootCallback->edgeColor( ); QTableWidgetItem* edgeColorItem = - this->ui->tableWidget->item( int(EDGE_COLOR_KEY), 0 ); + this->ui->tableWidget->item( int(EDGE_COLOR_KEY), 0 ); QTableWidgetItem* edgeWidthItem = - this->ui->tableWidget->item( int(EDGE_WIDTH_KEY), 0 ); + this->ui->tableWidget->item( int(EDGE_WIDTH_KEY), 0 ); QTableWidgetItem* vertexColorItem = - this->ui->tableWidget->item( int(VERTEX_COLOR_KEY), 0 ); + this->ui->tableWidget->item( int(VERTEX_COLOR_KEY), 0 ); QTableWidgetItem* vertexRadiusItem = - this->ui->tableWidget->item( int(VERTEX_RADIUS_KEY), 0 ); - QTableWidgetItem* deleteCurveModeItem = - this->ui->tableWidget->item( int(DELETE_CURVE_MODE_KEY), 0 ); - QTableWidgetItem* gridSizeItem = - this->ui->tableWidget->item( int( GRID_SIZE_KEY ), 0 ); + this->ui->tableWidget->item( int(VERTEX_RADIUS_KEY), 0 ); QTableWidgetItem* gridColorItem = - this->ui->tableWidget->item( int( GRID_COLOR_KEY ), 0 ); + this->ui->tableWidget->item( int( GRID_COLOR_KEY ), 0 ); QTableWidgetItem* envelopeEdgeColorItem = - this->ui->tableWidget->item( int(ENVELOPE_EDGE_COLOR_KEY), 0 ); + this->ui->tableWidget->item( int(ENVELOPE_EDGE_COLOR_KEY), 0 ); QTableWidgetItem* envelopeEdgeWidthItem = - this->ui->tableWidget->item( int(ENVELOPE_EDGE_WIDTH_KEY), 0 ); + this->ui->tableWidget->item( int(ENVELOPE_EDGE_WIDTH_KEY), 0 ); QTableWidgetItem* envelopeVertexColorItem = - this->ui->tableWidget->item( int(ENVELOPE_VERTEX_COLOR_KEY), 0 ); + this->ui->tableWidget->item( int(ENVELOPE_VERTEX_COLOR_KEY), 0 ); QTableWidgetItem* envelopeVertexRadiusItem = - this->ui->tableWidget->item( int(ENVELOPE_VERTEX_RADIUS_KEY), 0 ); + this->ui->tableWidget->item( int(ENVELOPE_VERTEX_RADIUS_KEY), 0 ); QTableWidgetItem* verticalRayEdgeColorItem = - this->ui->tableWidget->item( int(VERTICAL_RAY_EDGE_COLOR_KEY), 0 ); + this->ui->tableWidget->item( int(VERTICAL_RAY_EDGE_COLOR_KEY), 0 ); QTableWidgetItem* verticalRayEdgeWidthItem = - this->ui->tableWidget->item( int(VERTICAL_RAY_EDGE_WIDTH_KEY), 0 ); + this->ui->tableWidget->item( int(VERTICAL_RAY_EDGE_WIDTH_KEY), 0 ); // arrangement properties edgeColorItem->setData( Qt::DisplayRole, edgeColor ); @@ -197,14 +179,14 @@ void ArrangementDemoPropertiesDialog::updateUi( ) envelopeEdgeColorItem->setData( Qt::DisplayRole, envelopeEdgeColor ); envelopeEdgeColorItem->setData( Qt::DecorationRole, envelopeEdgeColor ); envelopeEdgeColorItem->setData( Qt::UserRole, - QVariant::fromValue( envelopeEdgeColor ) ); + QVariant::fromValue( envelopeEdgeColor ) ); envelopeEdgeWidthItem->setData( Qt::DisplayRole, envelopeEdgeWidth ); envelopeVertexColorItem->setData( Qt::DisplayRole, envelopeVertexColor ); envelopeVertexColorItem->setData( Qt::DecorationRole, envelopeVertexColor ); envelopeVertexColorItem->setData( Qt::UserRole, - QVariant::fromValue(envelopeVertexColor)); + QVariant::fromValue(envelopeVertexColor)); envelopeVertexRadiusItem->setData( Qt::DisplayRole, envelopeVertexRadius ); @@ -212,22 +194,12 @@ void ArrangementDemoPropertiesDialog::updateUi( ) verticalRayEdgeColorItem->setData( Qt::DisplayRole, verticalRayEdgeColor ); verticalRayEdgeColorItem->setData( Qt::DecorationRole, verticalRayEdgeColor ); verticalRayEdgeColorItem->setData( Qt::UserRole, - QVariant::fromValue(verticalRayEdgeColor)); + QVariant::fromValue(verticalRayEdgeColor)); verticalRayEdgeWidthItem->setData( Qt::DisplayRole, verticalRayEdgeWidth ); - // delete curve properties - DeleteCurveMode deleteCurveMode; - deleteCurveModeItem->setData( Qt::DisplayRole, - DeleteCurveMode::ToString( deleteCurveMode ) ); - deleteCurveModeItem->setData( Qt::UserRole, - QVariant::fromValue( deleteCurveMode ) ); - // grid properties - gridSizeItem->setData( Qt::DisplayRole, gridSize ); - gridColorItem->setData( Qt::DisplayRole, gridColor ); gridColorItem->setData( Qt::DecorationRole, gridColor ); gridColorItem->setData( Qt::UserRole, QVariant::fromValue( gridColor ) ); - } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.h index dd6158edd48..0db3916ef8f 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef ARRANGEMENT_DEMO_PROPERTIES_DIALOG_H #define ARRANGEMENT_DEMO_PROPERTIES_DIALOG_H @@ -27,23 +28,20 @@ class ArrangementDemoPropertiesDialog : public QDialog public: // keep this in order with the ui layout enum PropertyKey { - EDGE_COLOR_KEY, - EDGE_WIDTH_KEY, - VERTEX_COLOR_KEY, - VERTEX_RADIUS_KEY, - ENVELOPE_EDGE_COLOR_KEY, - ENVELOPE_EDGE_WIDTH_KEY, - ENVELOPE_VERTEX_COLOR_KEY, - ENVELOPE_VERTEX_RADIUS_KEY, - VERTICAL_RAY_EDGE_COLOR_KEY, - VERTICAL_RAY_EDGE_WIDTH_KEY, - DELETE_CURVE_MODE_KEY, - GRID_SIZE_KEY, - GRID_COLOR_KEY + EDGE_COLOR_KEY, /*!< color key */ + EDGE_WIDTH_KEY, /*!< width key */ + VERTEX_COLOR_KEY, /*!< vertex color */ + VERTEX_RADIUS_KEY, /*!< vertex radius */ + ENVELOPE_EDGE_COLOR_KEY, /*!< envelope color */ + ENVELOPE_EDGE_WIDTH_KEY, /*!< envelope size */ + ENVELOPE_VERTEX_COLOR_KEY, /*!< envelope vertex color */ + ENVELOPE_VERTEX_RADIUS_KEY, /*!< color key */ + VERTICAL_RAY_EDGE_COLOR_KEY, /*!< shooting ray color */ + VERTICAL_RAY_EDGE_WIDTH_KEY, /*!< shooting ray size */ + GRID_COLOR_KEY /*!< color of the grid */ }; - ArrangementDemoPropertiesDialog( ArrangementDemoWindow* parent_ = 0, - Qt::WindowFlags f = Qt::WindowType(0)); + ArrangementDemoPropertiesDialog( ArrangementDemoWindow* parent_ = 0 ); QVariant property( int index ); protected: diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.ui b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.ui index 825195306d2..e3808f40a2f 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.ui +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoPropertiesDialog.ui @@ -78,16 +78,6 @@ Vertical Ray Edge Width - - - Delete Curve Mode - - - - - Grid Size - - Grid Color diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.cpp index 83eb31ce518..80141270320 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,95 +7,400 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementDemoTab.h" +#include "ArrangementDemoGraphicsView.h" +#include "ArrangementGraphicsItem.h" +#include "DeleteCurveCallback.h" +#include "EnvelopeCallback.h" +#include "FillFaceCallback.h" +#include "GraphicsViewCurveInput.h" +#include "GridGraphicsItem.h" +#include "MergeEdgeCallback.h" +#include "PointLocationCallback.h" +#include "PointSnapper.h" +#include "SplitEdgeCallback.h" +#include "Utils/Utils.h" +#include "VerticalRayShootCallback.h" + +#include #include +#include -ArrangementDemoTabBase::ArrangementDemoTabBase( QWidget* parent ) : - QWidget( parent ), - graphicsView( new ArrangementDemoGraphicsView( this ) ), - scene( new QGraphicsScene( -100, -100, 100, 100 ) ), - layout( new QGridLayout( this ) ), - arrangementGraphicsItem( NULL ), - curveInputCallback( NULL ), - deleteCurveCallback( NULL ), - pointLocationCallback( NULL ), - verticalRayShootCallback( NULL ), - mergeEdgeCallback( NULL ), - splitEdgeCallback( NULL ), - envelopeCallback( NULL ), - fillFaceCallback( NULL ) + +ArrangementDemoTab::ArrangementDemoTab( + QWidget* parent, demo_types::TraitsType tt, CGAL::Object arrangement_) : + QWidget(parent), + GraphicsSceneMixin(new QGraphicsScene()), + graphicsView(new ArrangementDemoGraphicsView(this)), + layout(new QGridLayout(this)), + navigation(std::make_unique()), + activeCallback(nullptr), arrangementGraphicsItem(nullptr), + gridGraphicsItem(nullptr), ttype(tt), arrangement(arrangement_) { - this->setupUi( ); + this->setupUi(); + if (!this->arrangement) this->initArrangement(); + this->initComponents(); + this->setupCallbacks(); } -ArrangementDemoTabBase::~ArrangementDemoTabBase( ) +ArrangementDemoTab::~ArrangementDemoTab() { + this->unhookCallbacks(); + deleteArrangement(this->traitsType(), this->getArrangement()); } -void ArrangementDemoTabBase::setupUi( ) +void ArrangementDemoTab::setupUi() { - this->layout->addWidget( this->graphicsView, 0, 0, 1, 1 ); - this->graphicsView->setScene( this->scene ); - this->graphicsView->setMouseTracking( true ); + auto scene = this->getScene(); + + this->layout->addWidget(this->graphicsView, 0, 0); + this->graphicsView->setScene(scene); + + double MAX_WIDTH = (std::numeric_limits::max)() / 1048576; + + double xymin = -MAX_WIDTH / 2; + double wh = MAX_WIDTH; + scene->setSceneRect(xymin, xymin, wh, wh); + + this->getView()->installEventFilter(this->navigation.get()); + this->getView()->viewport()->installEventFilter(this->navigation.get()); } -QGraphicsScene* ArrangementDemoTabBase::getScene( ) const -{ - return this->scene; -} - -ArrangementDemoGraphicsView* ArrangementDemoTabBase::getView( ) const +QGraphicsView* ArrangementDemoTab::getView() const { return this->graphicsView; } CGAL::Qt::ArrangementGraphicsItemBase* -ArrangementDemoTabBase::getArrangementGraphicsItem( ) const +ArrangementDemoTab::getArrangementGraphicsItem() const { return this->arrangementGraphicsItem; } +GridGraphicsItem* ArrangementDemoTab::getGridGraphicsItem() const +{ + return this->gridGraphicsItem; +} + +void ArrangementDemoTab::showGrid(bool val) +{ + this->gridGraphicsItem->setVisible(val); +} + +void ArrangementDemoTab::setSnapToGrid(bool val) +{ + this->snapper->setSnapToGrid(val); +} + +void ArrangementDemoTab::setSnapToArrangement(bool val) +{ + this->snapper->setSnapToArrangement(val); +} + +bool ArrangementDemoTab::isSnapToGridEnabled() +{ + return this->snapper->isSnapToGridEnabled(); +} + +bool ArrangementDemoTab::isSnapToArrangementEnabled() +{ + return this->snapper->isSnapToArrangementEnabled(); +} + +bool ArrangementDemoTab::isGridVisible() +{ + return this->gridGraphicsItem->isVisible(); +} + CGAL::Qt::GraphicsViewCurveInputBase* -ArrangementDemoTabBase::getCurveInputCallback( ) const +ArrangementDemoTab::getCurveInputCallback() const { - return this->curveInputCallback; + return this->curveInputCallback.get(); } -CGAL::Qt::Callback* ArrangementDemoTabBase::getDeleteCurveCallback( ) const +CGAL::Qt::Callback* ArrangementDemoTab::getDeleteCurveCallback() const { - return this->deleteCurveCallback; + return this->deleteCurveCallback.get(); } -CGAL::Qt::Callback* ArrangementDemoTabBase::getPointLocationCallback( ) const +PointLocationCallbackBase* +ArrangementDemoTab::getPointLocationCallback() const { - return this->pointLocationCallback; + return this->pointLocationCallback.get(); } VerticalRayShootCallbackBase* -ArrangementDemoTabBase::getVerticalRayShootCallback( ) const +ArrangementDemoTab::getVerticalRayShootCallback() const { - return this->verticalRayShootCallback; + return this->verticalRayShootCallback.get(); } -CGAL::Qt::Callback* ArrangementDemoTabBase::getMergeEdgeCallback( ) const +MergeEdgeCallbackBase* ArrangementDemoTab::getMergeEdgeCallback() const { - return this->mergeEdgeCallback; + return this->mergeEdgeCallback.get(); } -SplitEdgeCallbackBase* ArrangementDemoTabBase::getSplitEdgeCallback( ) const +SplitEdgeCallbackBase* ArrangementDemoTab::getSplitEdgeCallback() const { - return this->splitEdgeCallback; + return this->splitEdgeCallback.get(); } -EnvelopeCallbackBase* ArrangementDemoTabBase::getEnvelopeCallback( ) const +EnvelopeCallbackBase* ArrangementDemoTab::getEnvelopeCallback() const { - return this->envelopeCallback; + return this->envelopeCallback.get(); } -FillFaceCallbackBase* ArrangementDemoTabBase::getFillFaceCallback( ) const +FillFaceCallbackBase* ArrangementDemoTab::getFillFaceCallback() const { - return this->fillFaceCallback; + return this->fillFaceCallback.get(); +} + +auto ArrangementDemoTab::getFillFaceColor() const -> QColor +{ + return this->fillFaceCallback->getColor(); +} + +void ArrangementDemoTab::setFillFaceColor(QColor color) +{ + this->fillFaceCallback->setColor(color); +} + +CGAL::Qt::GraphicsViewNavigation* +ArrangementDemoTab::getGraphicsViewNavigation() const +{ + return this->navigation.get(); +} + +void ArrangementDemoTab::activateCurveInputCallback( + CGAL::Qt::CurveType type) +{ + this->unhookCallbacks(); + + this->curveInputCallback->setCurveType(type); + this->getScene()->installEventFilter(this->curveInputCallback.get()); + this->activeCallback = this->curveInputCallback.get(); +} + +void ArrangementDemoTab::showLowerEnvelope(bool show) +{ + this->envelopeCallback->showLowerEnvelope(show); + this->update(); +} + +void ArrangementDemoTab::showUpperEnvelope(bool show) +{ + this->envelopeCallback->showUpperEnvelope(show); + this->update(); +} + +bool ArrangementDemoTab::isUpperEnvelopeShown() +{ + return this->envelopeCallback->isUpperEnvelopeShown(); +} + +bool ArrangementDemoTab::isLowerEnvelopeShown() +{ + return this->envelopeCallback->isLowerEnvelopeShown(); +} + +void ArrangementDemoTab::unhookCallbacks() +{ + if (this->activeCallback) + { + this->getScene()->removeEventFilter(this->activeCallback); + + activeCallback->reset(); + this->activeCallback = nullptr; + } +} + +void ArrangementDemoTab::unhookAndInstallEventFilter( + CGAL::Qt::Callback* obj) +{ + this->unhookCallbacks(); + this->getScene()->installEventFilter(obj); + this->activeCallback = obj; +} + +void ArrangementDemoTab::activateDeleteCurveCallback() +{ + // TODO: Create different button for modes of delete + if ( + this->activeCallback == + static_cast(this->deleteCurveCallback.get())) + { + auto deleteMode = this->deleteCurveCallback->getDeleteMode(); + if (deleteMode == DeleteMode::DeleteOriginatingCuve) + this->deleteCurveCallback->setDeleteMode(DeleteMode::DeleteEdge); + else + this->deleteCurveCallback->setDeleteMode( + DeleteMode::DeleteOriginatingCuve); + } + else + { + this->unhookAndInstallEventFilter(this->deleteCurveCallback.get()); + } +} + +void ArrangementDemoTab::activatePointLocationCallback() +{ + this->unhookAndInstallEventFilter(this->pointLocationCallback.get()); +} + +void ArrangementDemoTab::activateVerticalRayShootCallback(bool shootingUp) +{ + this->verticalRayShootCallback->setShootingUp(shootingUp); + this->unhookAndInstallEventFilter(this->verticalRayShootCallback.get()); +} + +void ArrangementDemoTab::activateMergeEdgeCallback() +{ + this->unhookAndInstallEventFilter(this->mergeEdgeCallback.get()); +} + +void ArrangementDemoTab::activateSplitEdgeCallback() +{ + this->unhookAndInstallEventFilter(this->splitEdgeCallback.get()); +} + +void ArrangementDemoTab::activateFillFaceCallback() +{ + this->unhookAndInstallEventFilter(this->fillFaceCallback.get()); +} + +void ArrangementDemoTab::updatePreferences(const Preferences& pref) +{ + auto agi = this->getArrangementGraphicsItem(); + auto envelopeCallback = this->getEnvelopeCallback(); + auto verticalRayShootCallback = this->getVerticalRayShootCallback(); + auto splitEdgeCallback = this->getSplitEdgeCallback(); + auto gridGraphicsItem = this->getGridGraphicsItem(); + + QPen edgesPen(QBrush(pref.edgeColor), pref.edgeWidth); + edgesPen.setCosmetic(true); + QPen verticesPen(QBrush(pref.vertexColor), pref.vertexRadius); + verticesPen.setCosmetic(true); + agi->setEdgesPen(edgesPen); + agi->setVerticesPen(verticesPen); + gridGraphicsItem->setAxesColor(pref.axesColor); + gridGraphicsItem->setGridColor(pref.gridColor); + envelopeCallback->setEnvelopeEdgeColor(pref.envelopeEdgeColor); + envelopeCallback->setEnvelopeEdgeWidth(pref.envelopeEdgeWidth); + envelopeCallback->setEnvelopeVertexColor(pref.envelopeVertexColor); + envelopeCallback->setEnvelopeVertexRadius(pref.envelopeVertexRadius); + verticalRayShootCallback->setEdgeColor(pref.verticalRayEdgeColor); + verticalRayShootCallback->setEdgeWidth(pref.verticalRayEdgeWidth); + splitEdgeCallback->setColor(pref.edgeColor); + + Q_EMIT modelChanged(); +} + +demo_types::TraitsType ArrangementDemoTab::traitsType() const +{ + return ttype; +} + +void ArrangementDemoTab::initArrangement() +{ + this->arrangement = createArrangement(this->traitsType()); +} + +void ArrangementDemoTab::initComponents() +{ + auto scene = this->getScene(); + + this->gridGraphicsItem = new GridGraphicsItem(); + + this->snapper = std::unique_ptr(PointSnapperBase::create( + this->traitsType(), scene, this->gridGraphicsItem, this->getArrangement())); + + this->curveInputCallback = + std::unique_ptr( + CGAL::Qt::GraphicsViewCurveInputBase::create( + this->traitsType(), this->getArrangement(), this, scene)); + this->deleteCurveCallback = + std::unique_ptr(DeleteCurveCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->pointLocationCallback = std::unique_ptr( + PointLocationCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->verticalRayShootCallback = + std::unique_ptr( + VerticalRayShootCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->mergeEdgeCallback = + std::unique_ptr(MergeEdgeCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->splitEdgeCallback = + std::unique_ptr(SplitEdgeCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->envelopeCallback = + std::unique_ptr(EnvelopeCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->fillFaceCallback = + std::unique_ptr(FillFaceCallbackBase::create( + this->traitsType(), this->getArrangement(), this)); + this->arrangementGraphicsItem = CGAL::Qt::ArrangementGraphicsItemBase::create( + this->traitsType(), this->getArrangement()); + + this->curveInputCallback->setPointSnapper(snapper.get()); + this->splitEdgeCallback->setPointSnapper(snapper.get()); + + scene->addItem(this->arrangementGraphicsItem); + scene->addItem(this->gridGraphicsItem); + + this->arrangementGraphicsItem->setScene(scene); + this->curveInputCallback->setScene(scene); + this->deleteCurveCallback->setScene(scene); + this->pointLocationCallback->setScene(scene); + this->verticalRayShootCallback->setScene(scene); + this->mergeEdgeCallback->setScene(scene); + this->splitEdgeCallback->setScene(scene); + this->envelopeCallback->setScene(scene); + this->fillFaceCallback->setScene(scene); +} + +void ArrangementDemoTab::setupCallbacks() +{ + // set up callbacks + QObject::connect( + this->curveInputCallback.get(), SIGNAL(modelChanged()), this, + SIGNAL(modelChanged())); + QObject::connect( + this->deleteCurveCallback.get(), SIGNAL(modelChanged()), this, + SIGNAL(modelChanged())); + QObject::connect( + this->fillFaceCallback.get(), SIGNAL(modelChanged()), this, + SIGNAL(modelChanged())); + QObject::connect( + this, SIGNAL(modelChanged()), this->arrangementGraphicsItem, + SLOT(modelChanged())); + QObject::connect( + this, SIGNAL(modelChanged()), this->envelopeCallback.get(), + SLOT(slotModelChanged())); + QObject::connect( + this->splitEdgeCallback.get(), SIGNAL(modelChanged()), this, + SIGNAL(modelChanged())); + QObject::connect( + this->mergeEdgeCallback.get(), SIGNAL(modelChanged()), this, + SIGNAL(modelChanged())); +} + +CGAL::Object ArrangementDemoTab::getArrangement() const +{ + return this->arrangement; +} + +void ArrangementDemoTab::adjustViewport() +{ + this->graphicsView->resetTransform(); + this->graphicsView->fitInView( + this->arrangementGraphicsItem->getInterestingViewport(), + Qt::KeepAspectRatio); + + Q_EMIT modelChanged(); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.h index aab9b72352c..54ece4964c2 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoTab.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,195 +7,148 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef ARRANGEMENT_DEMO_TAB_H #define ARRANGEMENT_DEMO_TAB_H +#include "GraphicsSceneMixin.h" +#include #include +#include +#include -#include "ArrangementGraphicsItem.h" -#include "ArrangementDemoGraphicsView.h" -#include "ArrangementCurveInputCallback.h" -#include "DeleteCurveCallback.h" -#include "PointLocationCallback.h" -#include "VerticalRayShootCallback.h" -#include "MergeEdgeCallback.h" -#include "SplitEdgeCallback.h" -#include "EnvelopeCallback.h" -#include "FillFaceCallback.h" - +class QGraphicsScene; class QGridLayout; +class ArrangementDemoGraphicsView; +class VerticalRayShootCallbackBase; +class EnvelopeCallbackBase; +class FillFaceCallbackBase; +class SplitEdgeCallbackBase; +class MergeEdgeCallbackBase; +class DeleteCurveCallbackBase; +class PointLocationCallbackBase; +class GridGraphicsItem; +class PointSnapperBase; -class ArrangementDemoTabBase : public QWidget +namespace CGAL +{ +namespace Qt +{ +class Callback; +class ArrangementGraphicsItemBase; +class ArrangementGraphicsItemBase; +class GraphicsViewCurveInputBase; +class GraphicsViewNavigation; +enum class CurveType; +} // namespace Qt +} // namespace CGAL + +namespace demo_types +{ +enum class TraitsType; +} + +class ArrangementDemoTab : public QWidget, public GraphicsSceneMixin { Q_OBJECT - Q_SIGNALS: +Q_SIGNALS: void modelChanged( ); public: - ArrangementDemoTabBase( QWidget* parent ); - virtual ~ArrangementDemoTabBase( ); + ArrangementDemoTab( + QWidget* parent, demo_types::TraitsType tt, CGAL::Object arrangement_); - virtual QGraphicsScene* getScene( ) const; - virtual ArrangementDemoGraphicsView* getView( ) const; + virtual ~ArrangementDemoTab(); - virtual CGAL::Qt::ArrangementGraphicsItemBase* getArrangementGraphicsItem( ) - const; - virtual CGAL::Qt::GraphicsViewCurveInputBase* getCurveInputCallback( ) const; - virtual CGAL::Qt::Callback* getDeleteCurveCallback( ) const; - virtual CGAL::Qt::Callback* getPointLocationCallback( ) const; - virtual VerticalRayShootCallbackBase* getVerticalRayShootCallback( ) const; - virtual CGAL::Qt::Callback* getMergeEdgeCallback( ) const; - virtual SplitEdgeCallbackBase* getSplitEdgeCallback( ) const; - virtual EnvelopeCallbackBase* getEnvelopeCallback( ) const; - virtual FillFaceCallbackBase* getFillFaceCallback( ) const; + CGAL::Object getArrangement() const; + demo_types::TraitsType traitsType() const; + + QGraphicsView* getView() const; + void showGrid(bool); + bool isGridVisible(); + void setSnapToGrid(bool); + void setSnapToArrangement(bool); + bool isSnapToGridEnabled(); + bool isSnapToArrangementEnabled(); + void adjustViewport(); + + auto getArrangementGraphicsItem() const + -> CGAL::Qt::ArrangementGraphicsItemBase*; + auto getGridGraphicsItem() const -> GridGraphicsItem*; + auto getCurveInputCallback() const -> CGAL::Qt::GraphicsViewCurveInputBase*; + auto getDeleteCurveCallback() const -> CGAL::Qt::Callback*; + auto getPointLocationCallback() const -> PointLocationCallbackBase*; + auto getVerticalRayShootCallback() const -> VerticalRayShootCallbackBase*; + auto getMergeEdgeCallback() const -> MergeEdgeCallbackBase*; + auto getSplitEdgeCallback() const -> SplitEdgeCallbackBase*; + auto getEnvelopeCallback() const -> EnvelopeCallbackBase*; + auto getFillFaceCallback() const -> FillFaceCallbackBase*; + auto getGraphicsViewNavigation() const -> CGAL::Qt::GraphicsViewNavigation*; + auto getFillFaceColor() const -> QColor; + void setFillFaceColor(QColor); + void activateCurveInputCallback(CGAL::Qt::CurveType); + void activateDeleteCurveCallback(); + void activatePointLocationCallback(); + void activateVerticalRayShootCallback(bool); + void activateMergeEdgeCallback(); + void activateSplitEdgeCallback(); + void activateEnvelopeCallback(); + void activateFillFaceCallback(); + void activatePanCallback(); + void showLowerEnvelope(bool); + void showUpperEnvelope(bool); + bool isUpperEnvelopeShown(); + bool isLowerEnvelopeShown(); + void unhookCallbacks(); + + struct Preferences + { + QColor edgeColor = {}; + QColor vertexColor = {}; + QColor envelopeEdgeColor = {}; + QColor envelopeVertexColor = {}; + QColor verticalRayEdgeColor = {}; + QColor axesColor = {}; + QColor gridColor = {}; + uint32_t edgeWidth = 0; + uint32_t vertexRadius = 0; + uint32_t envelopeEdgeWidth = 0; + uint32_t envelopeVertexRadius = 0; + uint32_t verticalRayEdgeWidth = 0; + }; + void updatePreferences(const Preferences&); protected: + void initArrangement(); + void initComponents(); + void setupCallbacks(); + virtual void setupUi( ); + void unhookAndInstallEventFilter(CGAL::Qt::Callback*); ArrangementDemoGraphicsView* graphicsView; - QGraphicsScene* scene; QGridLayout* layout; - CGAL::Qt::ArrangementGraphicsItemBase* arrangementGraphicsItem; - CGAL::Qt::GraphicsViewCurveInputBase* curveInputCallback; - CGAL::Qt::Callback* deleteCurveCallback; - CGAL::Qt::Callback* pointLocationCallback; - VerticalRayShootCallbackBase* verticalRayShootCallback; - CGAL::Qt::Callback* mergeEdgeCallback; - SplitEdgeCallbackBase* splitEdgeCallback; - EnvelopeCallbackBase* envelopeCallback; - FillFaceCallbackBase* fillFaceCallback; + std::unique_ptr curveInputCallback; + std::unique_ptr deleteCurveCallback; + std::unique_ptr pointLocationCallback; + std::unique_ptr verticalRayShootCallback; + std::unique_ptr mergeEdgeCallback; + std::unique_ptr splitEdgeCallback; + std::unique_ptr envelopeCallback; + std::unique_ptr fillFaceCallback; + std::unique_ptr snapper; + std::unique_ptr navigation; + CGAL::Qt::Callback* activeCallback; + CGAL::Qt::ArrangementGraphicsItemBase* arrangementGraphicsItem; + GridGraphicsItem* gridGraphicsItem; + + demo_types::TraitsType ttype; + CGAL::Object arrangement; }; // class ArrangementDemoTabBase -template < class Arr_ > -class ArrangementDemoTab : public ArrangementDemoTabBase -{ -public: - typedef ArrangementDemoTabBase Superclass; - typedef Arr_ Arrangement; - - ArrangementDemoTab( Arrangement* arrangement_, QWidget* parent = 0 ): - Superclass( parent ), - arrangement( arrangement_ ) - { - // std::cout << this->scene->views( ).size( ) << std::endl; - // set up demo components - this->arrangementGraphicsItem = - new CGAL::Qt::ArrangementGraphicsItem(this->arrangement); - this->curveInputCallback = - new ArrangementCurveInputCallback(this->arrangement, this); - this->deleteCurveCallback = - new DeleteCurveCallback( this->arrangement, this ); - this->pointLocationCallback = - new PointLocationCallback( this->arrangement, this ); - this->verticalRayShootCallback = - new VerticalRayShootCallback( this->arrangement, this ); - this->mergeEdgeCallback = - new MergeEdgeCallback( this->arrangement, this ); - this->splitEdgeCallback = - new SplitEdgeCallback( this->arrangement, this ); - this->envelopeCallback = - new EnvelopeCallback( this->arrangement, this ); - this->fillFaceCallback = - new FillFaceCallback( this->arrangement, this ); - - this->scene->addItem( this->arrangementGraphicsItem ); - this->arrangementGraphicsItem->setScene( this->scene ); - this->curveInputCallback->setScene( this->scene ); - this->deleteCurveCallback->setScene( this->scene ); - this->pointLocationCallback->setScene( this->scene ); - this->verticalRayShootCallback->setScene( this->scene ); - this->mergeEdgeCallback->setScene( this->scene ); - this->splitEdgeCallback->setScene( this->scene ); - this->envelopeCallback->setScene( this->scene ); - this->fillFaceCallback->setScene( this->scene ); - - // set up callbacks - this->scene->installEventFilter( this->curveInputCallback ); - QObject::connect(this->curveInputCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this->deleteCurveCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this->fillFaceCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this, SIGNAL(modelChanged()), - this->arrangementGraphicsItem, SLOT(modelChanged())); - QObject::connect(this, SIGNAL(modelChanged()), this->envelopeCallback, - SLOT(slotModelChanged())); - // TODO: Add a connection to update the demo window when the fill color - // changes - } - - void setArrangement( Arrangement* newArr ) - { - this->scene->removeItem( this->arrangementGraphicsItem ); - delete this->arrangementGraphicsItem; - delete this->curveInputCallback; - delete this->deleteCurveCallback; - delete this->pointLocationCallback; - delete this->verticalRayShootCallback; - delete this->mergeEdgeCallback; - delete this->splitEdgeCallback; - delete this->envelopeCallback; - delete this->fillFaceCallback; - - this->arrangement = newArr; - - this->arrangementGraphicsItem = - new CGAL::Qt::ArrangementGraphicsItem( this->arrangement ); - - this->curveInputCallback = - new ArrangementCurveInputCallback(this->arrangement, this); - this->deleteCurveCallback = - new DeleteCurveCallback( this->arrangement, this ); - this->pointLocationCallback = - new PointLocationCallback( this->arrangement, this ); - this->verticalRayShootCallback = - new VerticalRayShootCallback( this->arrangement, this ); - this->mergeEdgeCallback = - new MergeEdgeCallback( this->arrangement, this ); - this->splitEdgeCallback = - new SplitEdgeCallback( this->arrangement, this ); - this->envelopeCallback = - new EnvelopeCallback( this->arrangement, this ); - this->fillFaceCallback = - new FillFaceCallback( this->arrangement, this ); - - this->scene->addItem( this->arrangementGraphicsItem ); - this->arrangementGraphicsItem->setScene( this->scene ); - this->curveInputCallback->setScene( this->scene ); - this->deleteCurveCallback->setScene( this->scene ); - this->pointLocationCallback->setScene( this->scene ); - this->verticalRayShootCallback->setScene( this->scene ); - this->mergeEdgeCallback->setScene( this->scene ); - this->splitEdgeCallback->setScene( this->scene ); - this->envelopeCallback->setScene( this->scene ); - this->fillFaceCallback->setScene( this->scene ); - - this->scene->installEventFilter(this->curveInputCallback); - QObject::connect(this->curveInputCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this->deleteCurveCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this->fillFaceCallback, SIGNAL(modelChanged()), this, - SIGNAL(modelChanged())); - QObject::connect(this, SIGNAL(modelChanged()), - this->arrangementGraphicsItem, SLOT(modelChanged())); - QObject::connect(this, SIGNAL(modelChanged()), this->envelopeCallback, - SLOT(slotModelChanged())); - // TODO: Add a connection to update the demo window when the fill color - // changes - - Q_EMIT modelChanged( ); - } - -protected: - Arrangement* arrangement; - -}; // class ArrangementDemoTab - #endif // ARRANGEMENT_DEMO_TAB_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.cpp index 6170a701af7..0e9e2833ed4 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.cpp @@ -1,1248 +1,747 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementDemoWindow.h" -#include "NewTabDialog.h" -#include "OverlayDialog.h" +#include "AlgebraicCurveInputDialog.h" +#include "RationalCurveInputDialog.h" #include "ArrangementDemoPropertiesDialog.h" #include "ArrangementDemoTab.h" -#include "Conic_reader.h" - -#include "DeleteCurveMode.h" -#include "ArrangementGraphicsItem.h" - -#include +#include "NewTabDialog.h" +#include "OverlayDialog.h" +#include "GraphicsViewCurveInput.h" +#include "CurveInputMethods.h" +#include "ArrangementTypesUtils.h" +#include "ArrangementIO.h" +#include "Utils/Utils.h" #include -#include -#include #include +#include +#include +#include +#include +#include +#include -#include -#include -#include +#include + +#include "ui_ArrangementDemoWindow.h" + +using TraitsType = demo_types::TraitsType; ArrangementDemoWindow::ArrangementDemoWindow(QWidget* parent) : - CGAL::Qt::DemosMainWindow( parent ), - lastTabIndex(static_cast(-1)), - ui( new Ui::ArrangementDemoWindow ) + CGAL::Qt::DemosMainWindow(parent), ui(new Ui::ArrangementDemoWindow), + tabLabelCounter(1) { - this->setupUi( ); + this->setupUi(); - // set up the demo window - // ArrangementDemoTabBase* demoTab = - this->makeTab( SEGMENT_TRAITS ); - this->setupStatusBar( ); - this->setupOptionsMenu( ); - this->addAboutDemo( ":/help/about.html" ); - this->addAboutCGAL( ); + QObject::connect( + this->inputTypeGroup, SIGNAL(triggered(QAction*)), this, + SLOT(updateInputType(QAction*))); - // set up callbacks - QObject::connect( this->modeGroup, SIGNAL( triggered( QAction* ) ), - this, SLOT( updateMode( QAction* ) ) ); - QObject::connect( this->envelopeGroup, SIGNAL( triggered( QAction* ) ), - this, SLOT( updateEnvelope( QAction* ) ) ); - QObject::connect( this->snapGroup, SIGNAL( triggered( QAction* ) ), - this, SLOT( updateSnapping( QAction* ) ) ); + QObject::connect( + this->envelopeGroup, SIGNAL(triggered(QAction*)), this, + SLOT(updateEnvelope(QAction*))); - QObject::connect( this->conicTypeGroup, SIGNAL( triggered( QAction* ) ), - this, SLOT( updateConicType( QAction* ) ) ); + this->makeTab(TraitsType::SEGMENT_TRAITS); + + // Call inherited functions + this->setupStatusBar(); + // this->setupOptionsMenu(); + this->addAboutDemo(":/cgal/Arrangement_on_surface_2/about.html"); + this->addAboutCGAL(); } -ArrangementDemoWindow::~ArrangementDemoWindow() {} +ArrangementDemoWindow::~ArrangementDemoWindow() { } -ArrangementDemoTabBase* ArrangementDemoWindow::makeTab( TraitsType tt ) +void ArrangementDemoWindow::setupUi() { - static int tabLabelCounter = 1; - QString tabLabel; + this->ui->setupUi(this); - ArrangementDemoTabBase* demoTab; - Seg_arr* seg_arr; - Pol_arr* pol_arr; + this->modeGroup = new QActionGroup(this); + this->modeGroup->addAction(this->ui->actionDrag); + this->modeGroup->addAction(this->ui->actionInsert); + this->modeGroup->addAction(this->ui->actionDelete); + this->modeGroup->addAction(this->ui->actionPointLocation); + this->modeGroup->addAction(this->ui->actionRayShootingUp); + this->modeGroup->addAction(this->ui->actionRayShootingDown); + this->modeGroup->addAction(this->ui->actionMerge); + this->modeGroup->addAction(this->ui->actionSplit); + this->modeGroup->addAction(this->ui->actionFill); -#ifdef CGAL_USE_CORE - Conic_arr* conic_arr; -#endif + this->envelopeGroup = new QActionGroup(this); + this->envelopeGroup->addAction(this->ui->actionLowerEnvelope); + this->envelopeGroup->addAction(this->ui->actionUpperEnvelope); + this->envelopeGroup->setExclusive(false); - Lin_arr* lin_arr; - Arc_arr* arc_arr; - // Alg_seg_arr* alg_seg_arr; - CGAL::Object arr; + this->inputTypeGroup = new QActionGroup(this); + this->inputTypeGroup->addAction(this->ui->actionSegment); + this->inputTypeGroup->addAction(this->ui->actionPolyline); + this->inputTypeGroup->addAction(this->ui->actionCircle); + this->inputTypeGroup->addAction(this->ui->actionEllipse); + this->inputTypeGroup->addAction(this->ui->actionConicThreePoint); + this->inputTypeGroup->addAction(this->ui->actionConicFivePoint); + this->inputTypeGroup->addAction(this->ui->actionRay); + this->inputTypeGroup->addAction(this->ui->actionLine); + this->inputTypeGroup->addAction(this->ui->actionBezier); +} - switch ( tt ) - { - default: - case SEGMENT_TRAITS: - seg_arr = new Seg_arr; - demoTab = new ArrangementDemoTab< Seg_arr >( seg_arr, 0 ); - arr = CGAL::make_object( seg_arr ); - tabLabel = QString( "%1 - Segment" ).arg( tabLabelCounter++ ); - break; - case POLYLINE_TRAITS: - pol_arr = new Pol_arr; - demoTab = new ArrangementDemoTab< Pol_arr >( pol_arr, 0 ); - arr = CGAL::make_object( pol_arr ); - tabLabel = QString( "%1 - Polyline" ).arg( tabLabelCounter++ ); - break; - -#ifdef CGAL_USE_CORE - case CONIC_TRAITS: - conic_arr = new Conic_arr; - demoTab = new ArrangementDemoTab< Conic_arr >( conic_arr, 0 ); - arr = CGAL::make_object( conic_arr ); - tabLabel = QString( "%1 - Conic" ).arg( tabLabelCounter++ ); - break; -#endif - - case LINEAR_TRAITS: - lin_arr = new Lin_arr; - demoTab = new ArrangementDemoTab< Lin_arr >( lin_arr, 0 ); - arr = CGAL::make_object( lin_arr ); - tabLabel = QString( "%1 - Linear" ).arg( tabLabelCounter++ ); - break; - case CIRCULAR_ARC_TRAITS: - arc_arr = new Arc_arr; - demoTab = new ArrangementDemoTab< Arc_arr >( arc_arr, 0 ); - arr = CGAL::make_object( arc_arr ); - tabLabel = QString( "%1 - Circular Arc" ).arg( tabLabelCounter++ ); - break; - // case ALGEBRAIC_TRAITS: - // alg_seg_arr = new Alg_seg_arr; - // demoTab = new ArrangementDemoTab< Alg_seg_arr >( alg_seg_arr, 0 ); - // arr = CGAL::make_object( alg_seg_arr ); - // tabLabel = QString( "%1 - Algebraic" ).arg( tabLabelCounter++ ); - // break; - } - - this->arrangements.push_back( arr ); - this->tabs.push_back( demoTab ); - - QGraphicsView* view = demoTab->getView( ); - this->addNavigation( view ); - this->ui->tabWidget->addTab( demoTab, tabLabel ); - this->lastTabIndex = this->ui->tabWidget->currentIndex( ); - this->ui->tabWidget->setCurrentWidget( demoTab ); - - this->resetCallbackState( this->ui->tabWidget->currentIndex( ) ); - this->removeCallback( this->ui->tabWidget->currentIndex( ) ); - this->updateMode( this->modeGroup->checkedAction( ) ); - this->updateFillColorSwatch( ); +QString ArrangementDemoWindow::makeTabLabel(TraitsType tt) +{ + static const char* typeNames[] = { + "Segment", "Polyline", "Linear", "Conic", "Algebraic", + "Bezier", "Rational Functions" + }; + return QString("%1 - %2") + .arg(this->tabLabelCounter++) + .arg(typeNames[static_cast(tt)]); +} +ArrangementDemoTab* ArrangementDemoWindow::makeTab( + TraitsType tt, QString tabLabel, CGAL::Object arr_obj) +{ + ArrangementDemoTab* demoTab = new ArrangementDemoTab(this, tt, arr_obj); + if (tabLabel.isNull()) + tabLabel = makeTabLabel(tt); + this->addTab(demoTab, tabLabel); return demoTab; } -ArrangementDemoTabBase* ArrangementDemoWindow::getTab( unsigned int tabIndex ) - const +void ArrangementDemoWindow::addTab( + ArrangementDemoTab* demoTab, QString tabLabel) { - if (tabIndex > this->tabs.size()) return NULL; + this->tabs.push_back(demoTab); + + this->ui->tabWidget->addTab(demoTab, tabLabel); + this->ui->tabWidget->setCurrentWidget(demoTab); + + // avoid using addNavigation since it will cause memory leaks when there are + // multiple tabs (no way to delete the navigation item!) + QObject::connect( + demoTab->getGraphicsViewNavigation(), SIGNAL(mouseCoordinates(QString)), + xycoord, SLOT(setText(QString))); +} + +void ArrangementDemoWindow::resetActionGroups( + ArrangementDemoTab* tab, TraitsType tt) +{ + this->hideInsertMethods(); + this->ui->actionInsert->setChecked(false); + this->ui->actionDrag->setChecked(false); + this->ui->actionLowerEnvelope->setChecked(false); + this->ui->actionUpperEnvelope->setChecked(false); + this->ui->actionShowGrid->setChecked(tab->isGridVisible()); + this->ui->actionGridSnapMode->setChecked(tab->isSnapToGridEnabled()); + this->ui->actionArrangementSnapMode->setChecked( + tab->isSnapToArrangementEnabled()); + this->ui->actionLowerEnvelope->setChecked(tab->isLowerEnvelopeShown()); + this->ui->actionUpperEnvelope->setChecked(tab->isUpperEnvelopeShown()); + + if ( + tt != TraitsType::SEGMENT_TRAITS && tt != TraitsType::POLYLINE_TRAITS && + tt != TraitsType::LINEAR_TRAITS) + this->ui->actionArrangementSnapMode->setVisible(false); + else + this->ui->actionArrangementSnapMode->setVisible(true); + + // default action group is scrolling + this->ui->actionDrag->activate(QAction::Trigger); +} + +void ArrangementDemoWindow::resetCallbackState(ArrangementDemoTab* tab) +{ + if (tab) + { + tab->getView()->setDragMode(QGraphicsView::NoDrag); + tab->unhookCallbacks(); + } +} + +void ArrangementDemoWindow::updateEnvelope(QAction* newMode) +{ + auto currentTab = this->getCurrentTab(); + if (!currentTab) return; + + bool show = newMode->isChecked(); + if (newMode == this->ui->actionLowerEnvelope) + currentTab->showLowerEnvelope(show); + else if (newMode == this->ui->actionUpperEnvelope) + currentTab->showUpperEnvelope(show); +} + +void ArrangementDemoWindow::hideInsertMethods() +{ + this->ui->actionAddAlgebraicCurve->setVisible(false); + this->ui->actionAddAlgebraicCurve->setChecked(false); + this->ui->actionAddRationalCurve->setVisible(false); + this->ui->actionAddRationalCurve->setChecked(false); + this->ui->actionSegment->setVisible(false); + this->ui->actionSegment->setChecked(false); + this->ui->actionCircle->setVisible(false); + this->ui->actionCircle->setChecked(false); + this->ui->actionEllipse->setVisible(false); + this->ui->actionEllipse->setChecked(false); + this->ui->actionConicThreePoint->setVisible(false); + this->ui->actionConicThreePoint->setChecked(false); + this->ui->actionConicFivePoint->setVisible(false); + this->ui->actionConicFivePoint->setChecked(false); + this->ui->actionRay->setVisible(false); + this->ui->actionRay->setChecked(false); + this->ui->actionLine->setVisible(false); + this->ui->actionLine->setChecked(false); + this->ui->actionPolyline->setVisible(false); + this->ui->actionPolyline->setChecked(false); + this->ui->actionBezier->setVisible(false); + this->ui->actionBezier->setChecked(false); +} + +void ArrangementDemoWindow::showInsertMethods(demo_types::TraitsType tabType) +{ + switch(tabType) + { + case TraitsType::NONE: + return; + case TraitsType::SEGMENT_TRAITS: + this->ui->actionSegment->setVisible(true); + this->ui->actionSegment->activate(QAction::Trigger); + break; + case TraitsType::POLYLINE_TRAITS: + this->ui->actionPolyline->setVisible(true); + this->ui->actionPolyline->activate(QAction::Trigger); + break; + case TraitsType::LINEAR_TRAITS: + this->ui->actionSegment->setVisible(true); + this->ui->actionSegment->activate(QAction::Trigger); + this->ui->actionRay->setVisible(true); + this->ui->actionLine->setVisible(true); + break; +#ifdef CGAL_USE_CORE + case TraitsType::CONIC_TRAITS: + this->ui->actionSegment->setVisible(true); + this->ui->actionCircle->setVisible(true); + this->ui->actionEllipse->setVisible(true); + this->ui->actionConicThreePoint->setVisible(true); + this->ui->actionConicFivePoint->setVisible(true); + break; + case TraitsType::ALGEBRAIC_TRAITS: + this->ui->actionCircle->setVisible(true); + this->ui->actionCircle->activate(QAction::Trigger); + this->ui->actionEllipse->setVisible(true); + this->ui->actionLine->setVisible(true); + this->ui->actionAddAlgebraicCurve->setVisible(true); + break; + case TraitsType::BEZIER_TRAITS: + this->ui->actionBezier->setVisible(true); + this->ui->actionBezier->activate(QAction::Trigger); + break; + case TraitsType::RATIONAL_FUNCTION_TRAITS: + this->ui->actionAddRationalCurve->setVisible(true); + break; +#endif + default: + CGAL_error(); + } +} + +void ArrangementDemoWindow::updateInputType(QAction* a) +{ + auto tab = this->getCurrentTab(); + if (!tab) return; + + using namespace CGAL::Qt; + CurveType curveType = CurveType::None; + + if (a == this->ui->actionSegment) + curveType = CurveType::Segment; + else if (a == this->ui->actionPolyline) + curveType = CurveType::Polyline; + else if (a == this->ui->actionLine) + curveType = CurveType::Line; + else if (a == this->ui->actionRay) + curveType = CurveType::Ray; + else if (a == this->ui->actionCircle) + curveType = CurveType::Circle; + else if (a == this->ui->actionEllipse) + curveType = CurveType::Ellipse; + else if (a == this->ui->actionConicThreePoint) + curveType = CurveType::ThreePointCircularArc; + else if (a == this->ui->actionConicFivePoint) + curveType = CurveType::FivePointConicArc; + else if (a == this->ui->actionBezier) + curveType = CurveType::Bezier; + + tab->activateCurveInputCallback(curveType); +} + +void ArrangementDemoWindow::on_actionAddAlgebraicCurve_triggered() +{ +#ifdef CGAL_USE_CORE + AlgebraicCurveInputDialog newDialog; + + if (newDialog.exec() == QDialog::Accepted) + { + auto currentTab = this->getCurrentTab(); + + std::string expression = newDialog.getLineEditText(); + bool is_first_curve = false; + + auto cv = algebraicCurveFromExpression( + currentTab->getArrangement(), expression, + is_first_curve); + + if (!cv) + { + QMessageBox msgBox; + msgBox.setWindowTitle("Invalid Expression"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setText(QString::fromStdString("Unable to parse expression!")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } + + // adding curve to the arrangement + auto algCurveInputCallback = currentTab->getCurveInputCallback(); + algCurveInputCallback->generate(cv); + if (is_first_curve) currentTab->adjustViewport(); + } +#endif +} + +void ArrangementDemoWindow::on_actionAddRationalCurve_triggered() +{ +#ifdef CGAL_USE_CORE + RationalCurveInputDialog newDialog; + + if (newDialog.exec() == QDialog::Accepted) + { + auto currentTab = this->getCurrentTab(); + + std::string num = newDialog.getNumeratorText(); + std::string den = newDialog.getDenominatorText(); + + bool is_first_curve = false; + + auto cv = rationalCurveFromExpression( + currentTab->getArrangement(), num, den, is_first_curve); + + if (!cv) + { + QMessageBox msgBox; + msgBox.setWindowTitle("Invalid Expression"); + msgBox.setIcon(QMessageBox::Critical); + msgBox.setText(QString::fromStdString("Unable to parse expression!")); + msgBox.setStandardButtons(QMessageBox::Ok); + msgBox.exec(); + return; + } + + // adding curve to the arrangement + auto algCurveInputCallback = currentTab->getCurveInputCallback(); + algCurveInputCallback->generate(cv); + if (is_first_curve) currentTab->adjustViewport(); + } +#endif +} + +void ArrangementDemoWindow::on_actionQuit_triggered() { qApp->exit(); } + +void ArrangementDemoWindow::on_actionNewTab_triggered() +{ + NewTabDialog newTabDialog; + if (newTabDialog.exec() == QDialog::Accepted) + { + int id = newTabDialog.checkedId(); + this->makeTab(static_cast(id)); + } +} + +void ArrangementDemoWindow::on_tabWidget_currentChanged(int) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + auto tt = currentTab->traitsType(); + this->resetCallbackState(currentTab); + this->resetActionGroups(currentTab, tt); + this->updateFillColorSwatch(currentTab); + } +} + +void ArrangementDemoWindow::on_actionInsert_toggled(bool checked) +{ + this->hideInsertMethods(); + + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (checked) + this->showInsertMethods(currentTab->traitsType()); + else + this->resetCallbackState(currentTab); + } +} + +void ArrangementDemoWindow::on_actionDrag_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + // TODO: Move this to DemoTab + QGraphicsView* activeView = currentTab->getView(); + if (!checked) + activeView->setDragMode(QGraphicsView::NoDrag); + else + activeView->setDragMode(QGraphicsView::ScrollHandDrag); + } +} + +void ArrangementDemoWindow::on_actionDelete_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab && !checked) + this->resetCallbackState(currentTab); +} + +void ArrangementDemoWindow::on_actionDelete_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + currentTab->activateDeleteCurveCallback(); +} + +void ArrangementDemoWindow::on_actionPointLocation_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activatePointLocationCallback(); + } +} + +void ArrangementDemoWindow::on_actionRayShootingUp_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activateVerticalRayShootCallback(true); + } +} + +void ArrangementDemoWindow::on_actionRayShootingDown_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activateVerticalRayShootCallback(false); + } +} + +void ArrangementDemoWindow::on_actionMerge_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activateMergeEdgeCallback(); + } +} + +void ArrangementDemoWindow::on_actionSplit_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activateSplitEdgeCallback(); + } +} + +void ArrangementDemoWindow::on_actionFill_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + if (!checked) + this->resetCallbackState(currentTab); + else + currentTab->activateFillFaceCallback(); + } +} + + +void ArrangementDemoWindow::on_actionShowGrid_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + currentTab->showGrid(checked); + if (!checked && this->ui->actionGridSnapMode->isChecked()) + this->ui->actionGridSnapMode->activate(QAction::Trigger); + } +} + +void ArrangementDemoWindow::on_actionGridSnapMode_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + currentTab->setSnapToGrid(checked); + if (checked && !this->ui->actionShowGrid->isChecked()) + this->ui->actionShowGrid->activate(QAction::Trigger); + } +} + +void ArrangementDemoWindow::on_actionArrangementSnapMode_toggled(bool checked) +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + currentTab->setSnapToArrangement(checked); + } +} + +void ArrangementDemoWindow::on_actionCloseTab_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (!currentTab) return; + + // delete the tab + auto currentTabIndex = this->ui->tabWidget->currentIndex(); + this->ui->tabWidget->removeTab(currentTabIndex); + + // release memory + delete currentTab; + + // remove the tab + this->tabs.erase(this->tabs.begin() + currentTabIndex); +} + +void ArrangementDemoWindow::on_actionZoomIn_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + QGraphicsView* view = currentTab->getView(); + view->scale(2.0, 2.0); + } +} + +void ArrangementDemoWindow::on_actionZoomOut_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + { + QGraphicsView* view = currentTab->getView(); + view->scale(0.5, 0.5); + } +} + +void ArrangementDemoWindow::on_actionZoomReset_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (currentTab) + currentTab->adjustViewport(); +} + +void ArrangementDemoWindow::on_actionFillColor_triggered() +{ + auto currentTab = this->getCurrentTab(); + if (!currentTab) return; + + QColor fillColor = currentTab->getFillFaceColor(); + + QColor selectedColor = QColorDialog::getColor(fillColor); + if (selectedColor.isValid()) + { + currentTab->setFillFaceColor(selectedColor); + this->updateFillColorSwatch(currentTab); + } +} + +void ArrangementDemoWindow::updateFillColorSwatch(ArrangementDemoTab* tab) +{ + if (!tab) return; + + QColor fillColor = tab->getFillFaceColor(); + if (!fillColor.isValid()) { fillColor = ::Qt::black; } + + QPixmap fillColorPixmap(16, 16); + fillColorPixmap.fill(fillColor); + QIcon fillColorIcon(fillColorPixmap); + this->ui->actionFillColor->setIcon(fillColorIcon); +} + +ArrangementDemoTab* ArrangementDemoWindow::getCurrentTab() +{ + int tabIndex = this->ui->tabWidget->currentIndex(); + if (tabIndex == -1) return nullptr; + return this->tabs[tabIndex]; } -ArrangementDemoTabBase* ArrangementDemoWindow::getCurrentTab( ) const +void ArrangementDemoWindow::on_actionOverlay_triggered() { - int currentIndex = this->ui->tabWidget->currentIndex( ); - if ( currentIndex == -1 ) - return NULL; + std::vector arr_infos; + for (int i = 0; i < this->ui->tabWidget->count(); ++i) + { + // this assumes that all tabs are of type ArrangementDemoTab + ArrangementDemoTab* tab = + static_cast(this->ui->tabWidget->widget(i)); - ArrangementDemoTabBase* res = this->tabs[ currentIndex ]; - return res; -} + arr_infos.push_back({ + i, tab->traitsType(), this->ui->tabWidget->tabText(i)}); + } -std::vector< QString > ArrangementDemoWindow::getTabLabels( ) const -{ - std::vector< QString > res; - for ( int i = 0; i < this->ui->tabWidget->count( ); ++i ) + OverlayDialog overlayDialog{this, arr_infos}; + if (overlayDialog.exec() == QDialog::Accepted) { - res.push_back( this->ui->tabWidget->tabText( i ) ); - } - return res; -} + std::vector arrs; + auto selected_arrs = overlayDialog.selectedArrangements(); + if (selected_arrs.empty()) return; -std::vector< CGAL::Object > ArrangementDemoWindow::getArrangements( ) const -{ - std::vector< CGAL::Object > res; - for ( unsigned int i = 0; i < this->arrangements.size( ); ++i ) - { - res.push_back( this->arrangements[ i ] ); - } - return res; -} + demo_types::TraitsType overlay_tt = + static_cast( + this->ui->tabWidget->widget(selected_arrs[0])) + ->traitsType(); -void ArrangementDemoWindow::setupUi( ) -{ - this->ui->setupUi( this ); + for (auto idx : selected_arrs) + { + ArrangementDemoTab* tab = + static_cast(this->ui->tabWidget->widget(idx)); - this->modeGroup = new QActionGroup( this ); - this->modeGroup->addAction( this->ui->actionDrag ); - this->modeGroup->addAction( this->ui->actionInsert ); - this->modeGroup->addAction( this->ui->actionDelete ); - this->modeGroup->addAction( this->ui->actionPointLocation ); - this->modeGroup->addAction( this->ui->actionRayShootingUp ); - this->modeGroup->addAction( this->ui->actionRayShootingDown ); - this->modeGroup->addAction( this->ui->actionMerge ); - this->modeGroup->addAction( this->ui->actionSplit ); - this->modeGroup->addAction( this->ui->actionFill ); - this->activeModes.push_back( this->ui->actionInsert ); + arrs.push_back(tab->getArrangement()); + } - this->envelopeGroup = new QActionGroup( this ); - this->envelopeGroup->addAction( this->ui->actionLowerEnvelope ); - this->envelopeGroup->addAction( this->ui->actionUpperEnvelope ); - this->envelopeGroup->setExclusive( false ); + auto arr_obj = makeOverlayArrangement(arrs); + if (arr_obj) + { + QString tab_label = QString("%1 (Overlay)").arg(makeTabLabel(overlay_tt)); + auto tab = makeTab(overlay_tt, tab_label, arr_obj); - this->snapGroup = new QActionGroup( this ); - this->snapGroup->addAction( this->ui->actionSnapMode ); - this->snapGroup->addAction( this->ui->actionGridSnapMode ); - this->snapGroup->setExclusive( false ); - this->ui->actionGridSnapMode->setEnabled( false ); - - this->conicTypeGroup = new QActionGroup( this ); - this->conicTypeGroup->addAction( this->ui->actionConicSegment ); - this->conicTypeGroup->addAction( this->ui->actionConicCircle ); - this->conicTypeGroup->addAction( this->ui->actionConicEllipse ); - this->conicTypeGroup->addAction( this->ui->actionConicThreePoint ); - this->conicTypeGroup->addAction( this->ui->actionConicFivePoint ); - this->conicTypeGroup->addAction( this->ui->actionCurveRay ); - this->conicTypeGroup->addAction( this->ui->actionCurveLine ); - - this->updateFillColorSwatch( ); -} - -void ArrangementDemoWindow::updateMode( QAction* newMode ) -{ - // QWidget* widget = this->ui->tabWidget->currentWidget( ); - // ArrangementDemoTabBase* demoTab = - // static_cast< ArrangementDemoTabBase* >( widget ); - const unsigned int TabIndex = this->ui->tabWidget->currentIndex( ); - if (TabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* activeTab = this->tabs[ TabIndex ]; - QGraphicsScene* activeScene = activeTab->getScene( ); - QGraphicsView* activeView = activeTab->getView( ); - - this->resetCallbackState( TabIndex ); - this->removeCallback( TabIndex ); - - // update the active mode - this->activeModes.at( 0 ) = newMode; - - // hook up the new active mode - if ( newMode == this->ui->actionInsert ) - { - activeScene->installEventFilter( activeTab->getCurveInputCallback( ) ); - } - else if ( newMode == this->ui->actionDrag ) - { - activeView->setDragMode( QGraphicsView::ScrollHandDrag ); - } - else if ( newMode == this->ui->actionDelete ) - { - activeScene->installEventFilter( activeTab->getDeleteCurveCallback( ) ); - } - else if ( newMode == this->ui->actionPointLocation ) - { - activeScene->installEventFilter( activeTab->getPointLocationCallback( ) ); - } - else if ( newMode == this->ui->actionRayShootingUp ) - { - // -y is up for Qt, so we shoot down - activeTab->getVerticalRayShootCallback( )->setShootingUp( true ); - activeScene->installEventFilter( activeTab->getVerticalRayShootCallback()); - } - else if ( newMode == this->ui->actionRayShootingDown ) - { - // the bottom of the viewport for Qt is +y, so we shoot up - activeTab->getVerticalRayShootCallback( )->setShootingUp( false ); - activeScene->installEventFilter( activeTab->getVerticalRayShootCallback()); - } - else if ( newMode == this->ui->actionMerge ) - { - activeScene->installEventFilter( activeTab->getMergeEdgeCallback( ) ); - } - else if ( newMode == this->ui->actionSplit ) - { - activeScene->installEventFilter( activeTab->getSplitEdgeCallback( ) ); - } - else if ( newMode == this->ui->actionFill ) - { - activeScene->installEventFilter( activeTab->getFillFaceCallback( ) ); - } - this->updateFillColorSwatch( ); -} - -void ArrangementDemoWindow::resetCallbackState( unsigned int tabIndex ) -{ - if (tabIndex == static_cast(-1) - || tabIndex >= this->tabs.size( )) return; - - ArrangementDemoTabBase* activeTab = this->tabs[ tabIndex ]; - - QAction* activeMode = this->activeModes.at( 0 ); - - // unhook the old active mode - if ( activeMode == this->ui->actionInsert ) - { } - else if ( activeMode == this->ui->actionDrag ) - { } - else if ( activeMode == this->ui->actionDelete ) - { - activeTab->getDeleteCurveCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionPointLocation ) - { - activeTab->getPointLocationCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionRayShootingUp ) - { - activeTab->getVerticalRayShootCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionRayShootingDown ) - { - activeTab->getVerticalRayShootCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionMerge ) - { - activeTab->getMergeEdgeCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionSplit ) - { - activeTab->getSplitEdgeCallback( )->reset( ); - } - else if ( activeMode == this->ui->actionFill ) - { - activeTab->getFillFaceCallback( )->reset( ); + tab->adjustViewport(); + } } } -void ArrangementDemoWindow::removeCallback( unsigned int tabIndex ) +void ArrangementDemoWindow::on_actionSaveAs_triggered() { - if (tabIndex == static_cast(-1)) return; - - ArrangementDemoTabBase* activeTab = this->tabs[ tabIndex ]; - QGraphicsScene* activeScene = activeTab->getScene( ); - QGraphicsView* activeView = activeTab->getView( ); -#if 0 - QAction* activeMode = this->activeModes[ tabIndex ]; -#endif - - activeScene->removeEventFilter( activeTab->getCurveInputCallback( ) ); - activeView->setDragMode( QGraphicsView::NoDrag ); - activeScene->removeEventFilter( activeTab->getDeleteCurveCallback( ) ); - activeScene->removeEventFilter( activeTab->getPointLocationCallback( ) ); - activeScene->removeEventFilter( activeTab->getVerticalRayShootCallback( ) ); - activeScene->removeEventFilter( activeTab->getMergeEdgeCallback( ) ); - activeScene->removeEventFilter( activeTab->getSplitEdgeCallback( ) ); - activeScene->removeEventFilter( activeTab->getVerticalRayShootCallback( ) ); - activeScene->removeEventFilter( activeTab->getFillFaceCallback( ) ); - - // unhook the old active mode -#if 0 - if ( activeMode == this->ui->actionInsert ) - { - activeScene->removeEventFilter( activeTab->getCurveInputCallback( ) ); - } - else if ( activeMode == this->ui->actionDrag ) - { - activeView->setDragMode( QGraphicsView::NoDrag ); - } - else if ( activeMode == this->ui->actionDelete ) - { - activeScene->removeEventFilter( activeTab->getDeleteCurveCallback( ) ); - } - else if ( activeMode == this->ui->actionPointLocation ) - { - activeScene->removeEventFilter( activeTab->getPointLocationCallback( ) ); - } - else if ( activeMode == this->ui->actionRayShootingUp ) - { - activeScene->removeEventFilter( activeTab->getVerticalRayShootCallback( ) ); - } - else if ( activeMode == this->ui->actionRayShootingDown ) - { - activeScene->removeEventFilter( activeTab->getVerticalRayShootCallback( ) ); - } - else if ( activeMode == this->ui->actionMerge ) - { - activeScene->removeEventFilter( activeTab->getMergeEdgeCallback( ) ); - } - else if ( activeMode == this->ui->actionSplit ) - { - activeScene->removeEventFilter( activeTab->getSplitEdgeCallback( ) ); - } -#endif -} - -void ArrangementDemoWindow::updateFillColorSwatch( ) -{ - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (currentTabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* currentTab = this->tabs[ currentTabIndex ]; - FillFaceCallbackBase* fillFaceCallback = currentTab->getFillFaceCallback( ); - QColor fillColor = fillFaceCallback->getColor( ); - if ( !fillColor.isValid( ) ) - { - fillColor = ::Qt::black; - } - - QPixmap fillColorPixmap( 16, 16 ); - fillColorPixmap.fill( fillColor ); - QIcon fillColorIcon( fillColorPixmap ); - this->ui->actionFillColor->setIcon( fillColorIcon ); -} - -void ArrangementDemoWindow::openArrFile( QString filename ) -{ - int index = this->ui->tabWidget->currentIndex( ); - if ( index == -1 ) - { - QMessageBox::information( this, "Oops", "Create a new tab first" ); - return; - } - if ( filename.isNull( ) ) + auto currentTab = this->getCurrentTab(); + if (!currentTab) { + QMessageBox::information(this, "Oops", "Create a new tab first"); return; } - std::ifstream ifs( filename.toStdString( ).c_str( ) ); - CGAL::Object arr = this->arrangements[ index ]; - Seg_arr* seg; - Pol_arr* pol; + std::pair arr_pair = { + currentTab->getArrangement(), currentTab->traitsType() + }; -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif + QString filename = QFileDialog::getSaveFileName( + this, tr("Save file"), "", "Arrangement (*.arr)"); + if (filename.isNull()) return; - // Alg_seg_arr* alg; - if ( CGAL::assign( seg, arr ) ) - { - typedef CGAL::Arr_text_formatter Seg_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - typedef ArrangementDemoTab TabType; - - ArrFormatter arrFormatter; - CGAL::read( *seg, ifs, arrFormatter ); - this->arrangements[ index ] = CGAL::make_object( seg ); - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - tab->setArrangement( seg ); - } - else if ( CGAL::assign( pol, arr ) ) - { - typedef CGAL::Arr_text_formatter< Pol_arr > Pol_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - typedef ArrangementDemoTab< Pol_arr > TabType; - - ArrFormatter arrFormatter; - CGAL::read( *pol, ifs, arrFormatter ); - this->arrangements[ index ] = CGAL::make_object( pol ); - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - tab->setArrangement( pol ); - } - -#ifdef CGAL_USE_CORE - else if (CGAL::assign(conic, arr)) { -#if 0 - typedef CGAL::Arr_text_formatter Conic_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - ArrFormatter arrFormatter; - CGAL::read( *conic, ifs, arrFormatter ); - this->arrangements[ index ] = CGAL::make_object( conic ); - tab->setArrangement( conic ); -#endif - typedef ArrangementDemoTab< Conic_arr > TabType; - Conic_reader< Conic_arr::Geometry_traits_2 > conicReader; - std::vector< Conic_arr::Curve_2 > curve_list; - CGAL::Bbox_2 bbox; - conicReader.read_data( filename.toStdString( ).c_str( ), - std::back_inserter( curve_list ), bbox ); - this->arrangements[ index ] = CGAL::make_object( conic ); - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - - CGAL::insert( *conic, curve_list.begin(), curve_list.end() ); - tab->setArrangement( conic ); - //QMessageBox::information( this, "Oops", - // "Reading conic arrangement not supported" ); - } -#endif - - // else if ( CGAL::assign( alg, arr ) ) - // { - // typedef CGAL::Arr_text_formatter< Alg_seg_arr > Seg_text_formatter; - // typedef CGAL::Arr_with_history_text_formatter - // ArrFormatter; - // typedef ArrangementDemoTab< Alg_seg_arr > TabType; - - // ArrFormatter arrFormatter; - // CGAL::read( *alg, ifs, arrFormatter ); - // this->arrangements[ index ] = CGAL::make_object( alg ); - // TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - // tab->setArrangement( alg ); - // } - ifs.close( ); + QByteArray ba = filename.toLocal8Bit(); + std::ofstream ofs(ba.data()); + if (!ArrangementIO{}.write(arr_pair, ofs)) + QMessageBox::information(this, "Oops", "Error saving file!"); } -void ArrangementDemoWindow::openDatFile( QString filename ) +void ArrangementDemoWindow::on_actionOpen_triggered() { - int index = this->ui->tabWidget->currentIndex( ); - if ( index == -1 ) + QString filename = QFileDialog::getOpenFileName( + this, tr("Open file"), "", "Arrangement files (*.arr)"); + if (filename.isNull()) return; + + if (filename.endsWith(".arr")) { - QMessageBox::information( this, "Oops", "Create a new tab first" ); - return; - } - if ( filename.isNull( ) ) - { - return; - } - - std::ifstream inputFile( filename.toStdString( ).c_str( ) ); - CGAL::Object arr = this->arrangements[ index ]; - Seg_arr* seg; - Pol_arr* pol; - -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif - - // Alg_seg_arr* alg; - - // Creates an ofstream object named inputFile - if (! inputFile.is_open() ) // Always test file open - { - std::cerr << "Error opening input file" << std::endl; - return; - } - - Pol_traits traits; - Pol_traits::Construct_curve_2 poly_const = - traits.construct_curve_2_object(); - - - if ( CGAL::assign( pol, arr ) ) - { - pol->clear( ); - - std::vector points; - - unsigned int num_polylines; - inputFile >> num_polylines; - std::list pol_list; - - unsigned int i; - for (i = 0; i < num_polylines; i++) + auto tab = this->openArrFile(filename); + if (tab) { - unsigned int num_segments; - inputFile >> num_segments; - points.clear(); - unsigned int j; - for (j = 0; j < num_segments; j++) - { - int ix, iy; - inputFile >> ix >> iy; - points.push_back (Arr_pol_point_2(NT(ix),NT(iy))); - } - - Arr_pol_2 curve = poly_const(points.begin(), points.end()); - pol_list.push_back(curve); + tab->setParent(this); + this->addTab(tab, this->makeTabLabel(tab->traitsType())); + tab->adjustViewport(); } - CGAL::insert(*pol, pol_list.begin(), pol_list.end()); - - typedef ArrangementDemoTab< Pol_arr > TabType; - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - tab->setArrangement( pol ); - } - else if ( CGAL::assign( seg, arr ) ) - { - seg->clear( ); - - int count; - inputFile >> count; - int i; - std::list seg_list; - for (i = 0; i < count; i++) - { - NT x0, y0, x1, y1; - inputFile >> x0 >> y0 >> x1 >> y1; - - Arr_seg_point_2 p1(x0, y0); - Arr_seg_point_2 p2(x1, y1); - - Arr_seg_2 curve(p1, p2); - - seg_list.push_back(curve); - } - - CGAL::insert(*(seg), seg_list.begin(), seg_list.end()); - - typedef ArrangementDemoTab< Seg_arr > TabType; - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - tab->setArrangement( seg ); - } - -#ifdef CGAL_USE_CORE - else if (CGAL::assign( conic, arr)) { - conic->clear( ); - Conic_reader< Conic_arr::Geometry_traits_2 > reader; - std::list curve_list; - CGAL::Bbox_2 bbox; - reader.read_data( filename.toStdString().c_str(), - std::back_inserter(curve_list), bbox ); - CGAL::insert (*conic, curve_list.begin(), curve_list.end()); - - typedef ArrangementDemoTab< Conic_arr > TabType; - TabType* tab = static_cast< TabType* >( this->tabs[ index ] ); - tab->setArrangement( conic ); - } -#endif - - inputFile.close(); -} - -void ArrangementDemoWindow::updateEnvelope( QAction* newMode ) -{ - if ( this->ui->tabWidget->currentIndex( ) == -1 ) return; - ArrangementDemoTabBase* activeTab = - this->tabs[ this->ui->tabWidget->currentIndex( ) ]; - // QGraphicsScene* activeScene = activeTab->getScene( ); - // QGraphicsView* activeView = activeTab->getView( ); - - bool show = newMode->isChecked( ); - if ( newMode == this->ui->actionLowerEnvelope ) - { - activeTab->getEnvelopeCallback( )->showLowerEnvelope( show ); - } - else if ( newMode == this->ui->actionUpperEnvelope ) - { - activeTab->getEnvelopeCallback( )->showUpperEnvelope( show ); - } -} - -void ArrangementDemoWindow::updateSnapping( QAction* newMode ) -{ - ArrangementDemoTabBase* activeTab = - this->tabs[ this->ui->tabWidget->currentIndex( ) ]; - QGraphicsScene* activeScene = activeTab->getScene( ); - ArrangementDemoGraphicsView* activeView = activeTab->getView( ); - - bool enabled = newMode->isChecked( ); - if ( newMode == this->ui->actionSnapMode ) - { - activeTab->getCurveInputCallback( )->setSnappingEnabled( enabled ); - activeTab->getSplitEdgeCallback( )->setSnappingEnabled( enabled ); - if ( ! enabled ) - { - this->ui->actionGridSnapMode->setChecked( false ); - this->ui->actionGridSnapMode->setEnabled( false ); - activeTab->getCurveInputCallback( )->setSnapToGridEnabled( false ); - activeTab->getSplitEdgeCallback( )->setSnapToGridEnabled( false ); - } - else - { - this->ui->actionGridSnapMode->setEnabled( true ); - } - } - else if ( newMode == this->ui->actionGridSnapMode ) - { - activeTab->getCurveInputCallback( )->setSnapToGridEnabled( enabled ); - activeTab->getSplitEdgeCallback( )->setSnapToGridEnabled( enabled ); - activeView->setShowGrid( enabled ); - } - activeScene->update( ); -} - -void ArrangementDemoWindow::updateConicType( QAction* newType ) -{ - ArrangementDemoTabBase* activeTab = - this->tabs[ this->ui->tabWidget->currentIndex( ) ]; - // QGraphicsScene* activeScene = activeTab->getScene( ); - // ArrangementDemoGraphicsView* activeView = activeTab->getView( ); - -#ifdef CGAL_USE_CORE - Conic_arr* conic_arr; - bool isConicArr = - CGAL::assign( conic_arr, - this->arrangements[ this->ui->tabWidget->currentIndex( ) ] ); -#endif - - Lin_arr* lin_arr; - bool isLinearArr = - CGAL::assign( lin_arr, - this->arrangements[ this->ui->tabWidget->currentIndex( ) ] ); - - if ( isLinearArr ) - { - typedef Lin_arr::Geometry_traits_2 Line_geom_traits; - typedef CGAL::Qt::GraphicsViewCurveInput - LinearCurveInputCallback; - LinearCurveInputCallback* curveInputCallback = - ( LinearCurveInputCallback* ) activeTab->getCurveInputCallback( ); - if ( newType == this->ui->actionConicSegment ) - { - curveInputCallback->setCurveType( LinearCurveInputCallback::SEGMENT ); - } - else if ( newType == this->ui->actionCurveRay ) - { - curveInputCallback->setCurveType( LinearCurveInputCallback::RAY ); - } - else if ( newType == this->ui->actionCurveLine ) - { - curveInputCallback->setCurveType( LinearCurveInputCallback::LINE ); - } - //std::cout << "do nothing" << std::endl; - } - -#ifdef CGAL_USE_CORE - else if (isConicArr) { - // std::cout << "do something conic arr related" << std::endl; - typedef Conic_arr::Geometry_traits_2 Conic_geom_traits; - typedef CGAL::Qt::GraphicsViewCurveInput - ConicCurveInputCallback; - ConicCurveInputCallback* curveInputCallback = - ( ConicCurveInputCallback* ) activeTab->getCurveInputCallback( ); - if ( newType == this->ui->actionConicSegment ) - { - curveInputCallback->setConicType(ConicCurveInputCallback::CONIC_SEGMENT); - } - else if ( newType == this->ui->actionConicCircle ) - { - curveInputCallback->setConicType(ConicCurveInputCallback::CONIC_CIRCLE); - } - else if ( newType == this->ui->actionConicEllipse ) - { - curveInputCallback->setConicType(ConicCurveInputCallback::CONIC_ELLIPSE); - } - else if ( newType == this->ui->actionConicThreePoint ) - { - curveInputCallback->setConicType( ConicCurveInputCallback:: - CONIC_THREE_POINT ); - } - else if ( newType == this->ui->actionConicFivePoint ) - { - curveInputCallback->setConicType( ConicCurveInputCallback:: - CONIC_FIVE_POINT ); - } - } -#endif -} - -void ArrangementDemoWindow::on_actionSaveAs_triggered( ) -{ - int index = this->ui->tabWidget->currentIndex( ); - if ( index == -1 ) - return; - QString filename = - QFileDialog::getSaveFileName( this, tr( "Save file" ), - "", "Arrangement (*.arr)" ); - if ( filename.isNull( ) ) - return; - - std::ofstream ofs( filename.toStdString( ).c_str( ) ); - CGAL::Object arr = this->arrangements[ index ]; - Seg_arr* seg; - Pol_arr* pol; - -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif - - if ( CGAL::assign( seg, arr ) ) - { - typedef CGAL::Arr_text_formatter Seg_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - ArrFormatter arrFormatter; - CGAL::write( *seg, ofs, arrFormatter ); - } - else if ( CGAL::assign( pol, arr ) ) - { - typedef CGAL::Arr_text_formatter Pol_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - ArrFormatter arrFormatter; - CGAL::write( *pol, ofs, arrFormatter ); - } - -#ifdef CGAL_USE_CORE - else if (CGAL::assign(conic, arr)) { -#if 0 - typedef CGAL::Arr_text_formatter Conic_text_formatter; - typedef CGAL::Arr_with_history_text_formatter - ArrFormatter; - ArrFormatter arrFormatter; - CGAL::write( *conic, ofs, arrFormatter ); -#endif - ofs << conic->number_of_curves( ) << std::endl; - for ( Conic_arr::Curve_iterator it = conic->curves_begin( ); - it != conic->curves_end( ); ++it ) - { - if ( it->is_full_conic( ) ) - { - ofs << "F "; - ofs << it->r( ) << " "; - ofs << it->s( ) << " "; - ofs << it->t( ) << " "; - ofs << it->u( ) << " "; - ofs << it->v( ) << " "; - ofs << it->w( ) << " "; - ofs << std::endl; - } - else if ( it->orientation( ) == CGAL::COLLINEAR ) - { - ofs << "S "; - ofs << it->source( ) << " "; - ofs << it->target( ) << " "; - ofs << std::endl; - } - else - { - ofs << "A "; - ofs << it->r( ) << " "; - ofs << it->s( ) << " "; - ofs << it->t( ) << " "; - ofs << it->u( ) << " "; - ofs << it->v( ) << " "; - ofs << it->w( ) << " "; - if ( it->orientation( ) == CGAL::COUNTERCLOCKWISE ) - ofs << "1 "; - else if ( it->orientation( ) == CGAL::CLOCKWISE ) - ofs << "-1 "; - else - ofs << "0 "; - ofs << it->source( ) << " "; - ofs << it->target( ) << " "; - ofs << std::endl; - } - } - } -#endif - - ofs.close( ); -} - -void ArrangementDemoWindow::on_actionOpen_triggered( ) -{ - int index = this->ui->tabWidget->currentIndex( ); - if ( index == -1 ) - { - QMessageBox::information( this, "Oops", "Create a new tab first" ); - return; - } - QString filename = - QFileDialog::getOpenFileName( this, tr( "Open file" ), - "", "Arrangement files (*.arr *.dat);;All files (*.*)" ); - if ( filename.isNull( ) ) - return; - - if ( filename.endsWith( ".arr" ) ) - { - this->openArrFile( filename ); } else { - this->openDatFile( filename ); - } - - ArrangementDemoTabBase* currentTab = this->tabs[ index ]; - CGAL::Qt::ArrangementGraphicsItemBase* agi = - currentTab->getArrangementGraphicsItem( ); - QRectF bb = agi->boundingRect( ); - QGraphicsView* view = currentTab->getView( ); - // std::cout << bb.left( ) << " " << bb.bottom( ) << ", " << bb.right( ) - // << " " << bb.top( ) << std::endl; - if ( boost::math::isinf(bb.left( )) || - boost::math::isinf(bb.right( )) || - boost::math::isinf(bb.top( )) || - boost::math::isinf(bb.bottom( )) ) - { - // std::cout << "unbounded; using default bb" << std::endl; - bb = QRectF( -100, -100, 200, 200 ); - view->setSceneRect( bb ); - } - else - { - view->fitInView( bb, ::Qt::KeepAspectRatio ); - view->setSceneRect( bb ); - } -#if 0 - view->centerOn( bb.center( ) ); -#endif -} - -void ArrangementDemoWindow::on_actionQuit_triggered( ) -{ - qApp->exit( ); -} - -void ArrangementDemoWindow::on_actionNewTab_triggered( ) -{ - NewTabDialog* newTabDialog = new NewTabDialog; - if ( newTabDialog->exec( ) == QDialog::Accepted ) - { - int id = newTabDialog->checkedId( ); - if ( id == SEGMENT_TRAITS ) - { - this->makeTab( SEGMENT_TRAITS ); - } - else if ( id == POLYLINE_TRAITS ) - { - this->makeTab( POLYLINE_TRAITS ); - } - else if ( id == CONIC_TRAITS ) - { - this->makeTab( CONIC_TRAITS ); - } - else if ( id == LINEAR_TRAITS ) - { - this->makeTab( LINEAR_TRAITS ); - } - else if ( id == CIRCULAR_ARC_TRAITS ) - { - this->makeTab( CIRCULAR_ARC_TRAITS ); - } - // else if ( id == ALGEBRAIC_TRAITS ) - // { - // this->makeTab( ALGEBRAIC_TRAITS ); - // } - else - { - std::cout << "Sorry, this trait is not yet supported" << std::endl; - } - } - delete newTabDialog; -} - -void ArrangementDemoWindow::on_tabWidget_currentChanged( ) -{ - // std::cout << "Tab changed" << std::endl; - // disable the callback for the previously active tab - this->resetCallbackState( this->lastTabIndex ); - this->removeCallback( this->lastTabIndex ); - this->lastTabIndex = this->ui->tabWidget->currentIndex( ); - - this->updateMode( this->modeGroup->checkedAction( ) ); - - CGAL::Object arr; - if ( this->ui->tabWidget->currentIndex( ) != -1 ) - arr = this->arrangements[ this->ui->tabWidget->currentIndex( ) ]; - - // Seg_arr* seg; - // Pol_arr* pol; - Lin_arr* lin; - -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif - - if ( CGAL::assign( lin, arr ) ) - { - this->ui->actionConicSegment->setChecked( true ); - - this->ui->actionCurveRay->setVisible( true ); - this->ui->actionCurveLine->setVisible( true ); - - this->ui->actionConicCircle->setVisible( false ); - this->ui->actionConicEllipse->setVisible( false ); - this->ui->actionConicThreePoint->setVisible( false ); - this->ui->actionConicFivePoint->setVisible( false ); - - this->conicTypeGroup->setEnabled( true ); - } - -#ifdef CGAL_USE_CORE - else if (CGAL::assign( conic, arr)) { - this->ui->actionConicSegment->setChecked( true ); - - this->ui->actionCurveRay->setVisible( false ); - this->ui->actionCurveLine->setVisible( false ); - - this->ui->actionConicCircle->setVisible( true ); - this->ui->actionConicEllipse->setVisible( true ); - this->ui->actionConicThreePoint->setVisible( true ); - this->ui->actionConicFivePoint->setVisible( true ); - - this->conicTypeGroup->setEnabled( true ); - } -#endif - - else { // segment or polyline - this->ui->actionConicSegment->setChecked( true ); - - this->ui->actionCurveRay->setVisible( false ); - this->ui->actionCurveLine->setVisible( false ); - - this->ui->actionConicCircle->setVisible( false ); - this->ui->actionConicEllipse->setVisible( false ); - this->ui->actionConicThreePoint->setVisible( false ); - this->ui->actionConicFivePoint->setVisible( false ); - - this->conicTypeGroup->setEnabled( true ); + QMessageBox::information(this, "Oops", "Unsupported file format"); } } -void ArrangementDemoWindow::on_actionOverlay_triggered( ) +ArrangementDemoTab* ArrangementDemoWindow::openArrFile(QString filename) { - OverlayDialog* overlayDialog = new OverlayDialog( this ); - if ( overlayDialog->exec( ) == QDialog::Accepted ) - { - std::vector< CGAL::Object > arrs = overlayDialog->selectedArrangements( ); - if ( arrs.size( ) == 2 ) - { - Seg_arr* seg_arr; - Seg_arr* seg_arr2; - Pol_arr* pol_arr; - Pol_arr* pol_arr2; + if (filename.isNull()) return nullptr; -#ifdef CGAL_USE_CORE - Conic_arr* conic_arr; - Conic_arr* conic_arr2; -#endif + QByteArray filename_ba = filename.toLocal8Bit(); + std::ifstream ifs(filename_ba.data()); - Lin_arr* lin_arr; - Lin_arr* lin_arr2; - Arc_arr* arc_arr; - Arc_arr* arc_arr2; - // Alg_seg_arr* alg_arr; - // Alg_seg_arr* alg_arr2; - if ( CGAL::assign( seg_arr, arrs[ 0 ] ) && - CGAL::assign( seg_arr2, arrs[ 1 ] ) ) - { - this->makeOverlayTab( seg_arr, seg_arr2 ); - } - if ( CGAL::assign( pol_arr, arrs[ 0 ] ) && - CGAL::assign( pol_arr2, arrs[ 1 ] ) ) - { - this->makeOverlayTab( pol_arr, pol_arr2 ); - } + ArrangementDemoTab* tab = nullptr; -#ifdef CGAL_USE_CORE - if (CGAL::assign(conic_arr, arrs[0]) && CGAL::assign(conic_arr2, arrs[1])) - { - this->makeOverlayTab( conic_arr, conic_arr2 ); - } -#endif + std::pair arr_pair = + ArrangementIO{}.read(ifs); + if (arr_pair.first) + tab = + makeTab(arr_pair.second, makeTabLabel(arr_pair.second), arr_pair.first); - if ( CGAL::assign( lin_arr, arrs[ 0 ] ) && - CGAL::assign( lin_arr2, arrs[ 1 ] ) ) - { - this->makeOverlayTab( lin_arr, lin_arr2 ); - } - if ( CGAL::assign( arc_arr, arrs[ 0 ] ) && - CGAL::assign( arc_arr2, arrs[ 1 ] ) ) - { - this->makeOverlayTab( arc_arr, arc_arr2 ); - } - // if ( CGAL::assign( alg_arr, arrs[ 0 ] ) && - // CGAL::assign( alg_arr2, arrs[ 1 ] ) ) - // { - // this->makeOverlayTab( alg_arr, alg_arr2 ); - // } - -#if 0 - if ( CGAL::assign( conic_arr, arrs[ 0 ] ) || - CGAL::assign( conic_arr, arrs[ 1 ] ) ) - { - this->makeOverlayTab< Conic_arr >( arrs[ 0 ], arrs[ 1 ] ); - } - else if ( CGAL::assign( pol_arr, arrs[ 0 ] ) || - CGAL::assign( pol_arr, arrs[ 1 ] ) ) - { - this->makeOverlayTab< Pol_arr >( arrs[ 0 ], arrs[ 1 ] ); - } - else - { - this->makeOverlayTab< Seg_arr >( arrs[ 0 ], arrs[ 1 ] ); - } -#endif - } - } - delete overlayDialog; + return tab; } -void ArrangementDemoWindow::on_actionCloseTab_triggered( ) +void ArrangementDemoWindow::on_actionPreferences_triggered() { - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (! this->ui->tabWidget->count() || - (currentTabIndex == static_cast(-1))) - return; + auto currentTab = this->getCurrentTab(); + if (!currentTab) return; - // delete the tab - this->ui->tabWidget->removeTab( currentTabIndex ); - this->tabs.erase( this->tabs.begin( ) + currentTabIndex ); + ArrangementDemoPropertiesDialog dialog{this}; - // delete the arrangement - this->arrangements.erase( this->arrangements.begin( ) + currentTabIndex ); -} - -void ArrangementDemoWindow::on_actionPrintConicCurves_triggered( ) -{ - // int currentTabIndex = this->ui->tabWidget->currentIndex( ); - // Conic_arr* arr; - // if (currentTabIndex == static_cast(-1)) return; - // CGAL::Object o = this->arrangements[ currentTabIndex ]; - // if ( ! CGAL::assign( arr, o ) ) - // return; - // typedef typename Conic_arr::Curve_iterator Curve_iterator; - // // std::cout << arr->number_of_curves( ) << std::endl; - // Curve_iterator it; - // for (it = arr->curves_begin(); it != arr->curves_end(); ++it) { - // std::cout << *it << std::endl; - // if ( it->is_full_conic( ) ) - // { - // std::cout << "F "; - // std::cout << it->r( ) << " "; - // std::cout << it->s( ) << " "; - // std::cout << it->t( ) << " "; - // std::cout << it->u( ) << " "; - // std::cout << it->v( ) << " "; - // std::cout << it->w( ) << " "; - // std::cout << std::endl; - // } - // else if ( it->orientation( ) == CGAL::COLLINEAR ) - // { - // std::cout << "S "; - // std::cout << it->source( ) << " "; - // std::cout << it->target( ) << " "; - // std::cout << std::endl; - // } - // else - // { - // std::cout << "A "; - // std::cout << it->r( ) << " "; - // std::cout << it->s( ) << " "; - // std::cout << it->t( ) << " "; - // std::cout << it->u( ) << " "; - // std::cout << it->v( ) << " "; - // std::cout << it->w( ) << " "; - // if ( it->orientation( ) == CGAL::COUNTERCLOCKWISE ) - // std::cout << "1 "; - // else if ( it->orientation( ) == CGAL::CLOCKWISE ) - // std::cout << "-1 "; - // else - // std::cout << "0 "; - // std::cout << it->source( ) << " "; - // std::cout << it->target( ) << " "; - // std::cout << std::endl; - // } - // } -} - -void ArrangementDemoWindow::on_actionZoomIn_triggered( ) -{ - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (currentTabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* currentTab = this->tabs[ currentTabIndex ]; - QGraphicsView* view = currentTab->getView( ); - view->scale( 2.0, 2.0 ); -} - -void ArrangementDemoWindow::on_actionZoomOut_triggered( ) -{ - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (currentTabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* currentTab = this->tabs[ currentTabIndex ]; - QGraphicsView* view = currentTab->getView( ); - view->scale( 0.5, 0.5 ); -} - -void ArrangementDemoWindow::on_actionPreferences_triggered( ) -{ - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (currentTabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* currentTab = this->tabs[ currentTabIndex ]; - CGAL::Qt::ArrangementGraphicsItemBase* agi = - currentTab->getArrangementGraphicsItem( ); - ArrangementDemoGraphicsView* view = currentTab->getView( ); - EnvelopeCallbackBase* envelopeCallback = currentTab->getEnvelopeCallback( ); - VerticalRayShootCallbackBase* verticalRayShootCallback = - currentTab->getVerticalRayShootCallback( ); - SplitEdgeCallbackBase* splitEdgeCallback = currentTab->getSplitEdgeCallback( ); - -#if 0 - QPen vertexPen = agi->getVerticesPen( ); - QPen edgePen = agi->getEdgesPen( ); - QBrush vertexPenBrush = vertexPen.brush( ); - QColor vertexColor = vertexPenBrush.color( ); - QBrush edgePenBrush = edgePen.brush( ); - QColor edgeColor = edgePenBrush.color( ); -#endif - - ArrangementDemoPropertiesDialog* dialog = - new ArrangementDemoPropertiesDialog( this ); - if ( dialog->exec( ) == QDialog::Accepted ) + if (dialog.exec() == QDialog::Accepted) { typedef ArrangementDemoPropertiesDialog Dialog; + ArrangementDemoTab::Preferences pref; - QColor edgeColor = dialog->property(Dialog::EDGE_COLOR_KEY).value(); - - unsigned int edgeWidth = dialog->property(Dialog::EDGE_WIDTH_KEY).value(); - - QColor vertexColor = dialog->property(Dialog::VERTEX_COLOR_KEY).value(); - - unsigned int vertexRadius = dialog->property(Dialog::VERTEX_RADIUS_KEY).value(); - - QColor envelopeEdgeColor = dialog->property(Dialog::ENVELOPE_EDGE_COLOR_KEY).value(); - - unsigned int envelopeEdgeWidth = dialog->property(Dialog::ENVELOPE_EDGE_WIDTH_KEY).value(); - - QColor envelopeVertexColor = dialog->property(Dialog::ENVELOPE_VERTEX_COLOR_KEY).value(); - - unsigned int envelopeVertexRadius = dialog->property(Dialog::ENVELOPE_VERTEX_RADIUS_KEY).value(); - - QColor verticalRayEdgeColor = dialog->property(Dialog::VERTICAL_RAY_EDGE_COLOR_KEY).value(); - - unsigned int verticalRayEdgeWidth = dialog->property(Dialog::VERTICAL_RAY_EDGE_WIDTH_KEY).value(); - - DeleteCurveMode mode = dialog->property(Dialog::DELETE_CURVE_MODE_KEY).value(); - - unsigned int gridSize = dialog->property(Dialog::GRID_SIZE_KEY).value(); - - QColor gridColor = dialog->property(Dialog::GRID_COLOR_KEY).value(); - //end new for Qt5 version ! - - - QPen edgesPen(QBrush(edgeColor), edgeWidth); - QPen verticesPen(QBrush(vertexColor), vertexRadius); - agi->setEdgesPen( edgesPen ); - agi->setVerticesPen( verticesPen ); - agi->modelChanged( ); - view->setGridSize( gridSize ); - view->setGridColor( gridColor ); - envelopeCallback->setEnvelopeEdgeColor( envelopeEdgeColor ); - envelopeCallback->setEnvelopeEdgeWidth( envelopeEdgeWidth ); - envelopeCallback->setEnvelopeVertexColor( envelopeVertexColor ); - envelopeCallback->setEnvelopeVertexRadius( envelopeVertexRadius ); - verticalRayShootCallback->setEdgeColor( verticalRayEdgeColor ); - verticalRayShootCallback->setEdgeWidth( verticalRayEdgeWidth ); - splitEdgeCallback->setColor( edgeColor ); - -#if 0 - std::cout << edgeColor.name( ).toStdString( ) << std::endl; - std::cout << edgeWidth << std::endl; - std::cout << vertexColor.name( ).toStdString( ) << std::endl; - std::cout << vertexRadius << std::endl; - std::cout << DeleteCurveMode::ToString( mode ).toStdString( ) << std::endl; -#endif - - } -} - -void ArrangementDemoWindow::on_actionFillColor_triggered( ) -{ - unsigned int currentTabIndex = this->ui->tabWidget->currentIndex( ); - if (currentTabIndex == static_cast(-1)) return; - ArrangementDemoTabBase* currentTab = this->tabs[ currentTabIndex ]; - FillFaceCallbackBase* fillFaceCallback = currentTab->getFillFaceCallback( ); - QColor fillColor = fillFaceCallback->getColor( ); - - QColor selectedColor = QColorDialog::getColor( fillColor ); - if ( selectedColor.isValid( ) ) - { - fillFaceCallback->setColor( selectedColor ); - this->updateFillColorSwatch( ); + pref.edgeColor = dialog.property(Dialog::EDGE_COLOR_KEY).value(); + pref.edgeWidth = + dialog.property(Dialog::EDGE_WIDTH_KEY).value(); + pref.vertexColor = + dialog.property(Dialog::VERTEX_COLOR_KEY).value(); + pref.vertexRadius = + dialog.property(Dialog::VERTEX_RADIUS_KEY).value(); + pref.envelopeEdgeColor = + dialog.property(Dialog::ENVELOPE_EDGE_COLOR_KEY).value(); + pref.envelopeEdgeWidth = + dialog.property(Dialog::ENVELOPE_EDGE_WIDTH_KEY).value(); + pref.envelopeVertexColor = + dialog.property(Dialog::ENVELOPE_VERTEX_COLOR_KEY).value(); + pref.envelopeVertexRadius = + dialog.property(Dialog::ENVELOPE_VERTEX_RADIUS_KEY).value(); + pref.verticalRayEdgeColor = + dialog.property(Dialog::VERTICAL_RAY_EDGE_COLOR_KEY).value(); + pref.verticalRayEdgeWidth = + dialog.property(Dialog::VERTICAL_RAY_EDGE_WIDTH_KEY) + .value(); + pref.axesColor = dialog.property(Dialog::GRID_COLOR_KEY).value(); + pref.gridColor = pref.axesColor; + pref.gridColor.setAlphaF(0.5); + currentTab->updatePreferences(pref); } } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.h index 65d7c8d0df2..4c338e2a838 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.h @@ -1,138 +1,109 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef ARRANGEMENT_DEMO_WINDOW_H #define ARRANGEMENT_DEMO_WINDOW_H -#include "ArrangementGraphicsItem.h" -#include "ArrangementTypes.h" -#include "DeleteCurveCallback.h" -#include "PointLocationCallback.h" -#include "VerticalRayShootCallback.h" -#include "MergeEdgeCallback.h" -#include "SplitEdgeCallback.h" -#include "EnvelopeCallback.h" -#include "ArrangementDemoTab.h" - -#include -#include +#include #include -extern const char * hand_xpm[]; - #include +#include +#include -#include "ui_ArrangementDemoWindow.h" +namespace Ui +{ +class ArrangementDemoWindow; +} -//#include -//#include -//#include -//#include +namespace CGAL +{ +class Object; +namespace Qt +{ +class GraphicsViewNavigation; +} +} // namespace CGAL -namespace Ui { class ArrangementDemoWindow; } +namespace demo_types +{ +enum class TraitsType; +} +class ArrangementDemoTab; class QActionGroup; class ArrangementDemoWindow : public CGAL::Qt::DemosMainWindow { Q_OBJECT - public: -#if 0 - typedef Seg_traits::Point_2 Point; - typedef Seg_traits::Segment_2 Segment; -#endif - typedef enum TraitsType { - SEGMENT_TRAITS, - POLYLINE_TRAITS, - CONIC_TRAITS, - LINEAR_TRAITS, - CIRCULAR_ARC_TRAITS - // ALGEBRAIC_TRAITS - } TraitsType; - ArrangementDemoWindow(QWidget* parent = 0); +public: + ArrangementDemoWindow(QWidget* parent = nullptr); ~ArrangementDemoWindow(); - ArrangementDemoTabBase* makeTab( TraitsType tt ); - ArrangementDemoTabBase* getTab( unsigned int tabIndex ) const; - ArrangementDemoTabBase* getCurrentTab( ) const; - - std::vector< QString > getTabLabels( ) const; - std::vector< CGAL::Object > getArrangements( ) const; - - template < class ArrType > - void makeOverlayTab( ArrType* arr1, ArrType* arr2 ); + ArrangementDemoTab* getCurrentTab(); public Q_SLOTS: - void updateMode( QAction* a ); - void updateEnvelope( QAction* a ); - void updateSnapping( QAction* a ); - void updateConicType( QAction* a ); - void on_actionNewTab_triggered( ); - void on_actionSaveAs_triggered( ); - void on_actionOpen_triggered( ); - void on_actionQuit_triggered( ); - void on_tabWidget_currentChanged( ); - void on_actionOverlay_triggered( ); - void on_actionCloseTab_triggered( ); - void on_actionPrintConicCurves_triggered( ); - void on_actionZoomIn_triggered( ); - void on_actionZoomOut_triggered( ); - void on_actionPreferences_triggered( ); - void on_actionFillColor_triggered( ); - + void updateEnvelope(QAction*); + void updateInputType(QAction*); + void on_actionNewTab_triggered(); + void on_actionSaveAs_triggered(); + void on_actionOpen_triggered(); + void on_actionQuit_triggered(); + void on_tabWidget_currentChanged(int); + void on_actionOverlay_triggered(); + void on_actionCloseTab_triggered(); + void on_actionZoomIn_triggered(); + void on_actionZoomOut_triggered(); + void on_actionZoomReset_triggered(); + void on_actionPreferences_triggered(); + void on_actionFillColor_triggered(); + void on_actionInsert_toggled(bool); + void on_actionDrag_toggled(bool); + void on_actionDelete_toggled(bool); + void on_actionDelete_triggered(); + void on_actionPointLocation_toggled(bool); + void on_actionRayShootingUp_toggled(bool); + void on_actionRayShootingDown_toggled(bool); + void on_actionShowGrid_toggled(bool); + void on_actionGridSnapMode_toggled(bool); + void on_actionArrangementSnapMode_toggled(bool); + void on_actionMerge_toggled(bool); + void on_actionSplit_toggled(bool); + void on_actionFill_toggled(bool); + void on_actionAddAlgebraicCurve_triggered(); + void on_actionAddRationalCurve_triggered(); Q_SIGNALS: - void modelChanged( ); + void modelChanged(); protected: - void setupUi( ); - void resetCallbackState( unsigned int tabIndex ); - void removeCallback( unsigned int tabIndex ); - void updateFillColorSwatch( ); - - void openArrFile( QString filename ); - void openDatFile( QString filename ); - - std::vector< ArrangementDemoTabBase* > tabs; - std::vector< CGAL::Object > arrangements; - std::vector< QAction* > activeModes; // for the current tab; always size 1 - unsigned int lastTabIndex; + void setupUi(); + ArrangementDemoTab* makeTab( + demo_types::TraitsType, QString label = {}, CGAL::Object arr_obj = {}); + void addTab(ArrangementDemoTab*, QString); + void resetCallbackState(ArrangementDemoTab*); + void resetActionGroups(ArrangementDemoTab*, demo_types::TraitsType); + void hideInsertMethods(); + void showInsertMethods(demo_types::TraitsType); + void updateFillColorSwatch(ArrangementDemoTab*); + QString makeTabLabel(demo_types::TraitsType); + ArrangementDemoTab* openArrFile(QString filename); +private: Ui::ArrangementDemoWindow* ui; + std::vector tabs; QActionGroup* modeGroup; QActionGroup* envelopeGroup; - QActionGroup* snapGroup; - QActionGroup* conicTypeGroup; + QActionGroup* inputTypeGroup; + int tabLabelCounter; }; -template < class ArrType > -void -ArrangementDemoWindow:: -makeOverlayTab( ArrType* arr1, ArrType* arr2 ) -{ - QString tabLabel = QString( "Overlay Tab" ); - - ArrangementDemoTabBase* demoTab; - ArrType* overlayArr = new ArrType; - CGAL::Arr_default_overlay_traits< ArrType > defaultTraits; - - CGAL::overlay( *arr1, *arr2, *overlayArr, defaultTraits ); - - demoTab = new ArrangementDemoTab< ArrType >( overlayArr, 0 ); - this->arrangements.push_back( CGAL::make_object( overlayArr ) ); - this->tabs.push_back( demoTab ); - - QGraphicsView* view = demoTab->getView( ); - this->addNavigation( view ); - this->ui->tabWidget->addTab( demoTab, tabLabel ); - this->lastTabIndex = this->ui->tabWidget->currentIndex( ); -} - #endif // ARRANGEMENT_DEMO_WINDOW_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.qrc b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.qrc deleted file mode 100644 index 1747c51b58c..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.qrc +++ /dev/null @@ -1,31 +0,0 @@ - - - icons/demo_fill.xpm - icons/demo_conic_line.xpm - icons/demo_zoomin.xpm - icons/demo_zoomout.xpm - icons/yellow_icon.xpm - icons/red_icon.xpm - icons/green_icon.xpm - icons/blue_icon.xpm - icons/demo_conic_circle.xpm - icons/demo_conic_ellipse.xpm - icons/demo_conic_5points.xpm - icons/demo_conic_segment.xpm - icons/demo_conic_3points.xpm - icons/demo_snapvertex.xpm - icons/demo_conic_ray.xpm - icons/lower_env_xpm.xpm - icons/upper_env_xpm.xpm - icons/demo_snapgrid.xpm - icons/demo_split.xpm - icons/demo_merge.xpm - icons/demo_rayshoot_down.xpm - icons/demo_rayshoot_up.xpm - icons/demo_insert.xpm - icons/hand.xpm - icons/demo_delete.xpm - icons/demo_pointlocation.xpm - help/about.html - - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.ui b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.ui index c324ff18b68..cb38d287843 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.ui +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementDemoWindow.ui @@ -11,7 +11,7 @@ - MainWindow + 2D Arrangements Demo @@ -49,20 +49,27 @@ + - + + + - - - - - + + + + + + + + + @@ -103,11 +110,11 @@ &Edit - - - + + + @@ -130,12 +137,9 @@ true - - true - - - :/icons/demo_insert.xpm:/icons/demo_insert.xpm + + :/cgal/icons/insert.xpm:/cgal/icons/insert.xpm &Insert @@ -146,8 +150,8 @@ true - - :/icons/demo_delete.xpm:/icons/demo_delete.xpm + + :/cgal/icons/delete.xpm:/cgal/icons/delete.xpm &Delete @@ -158,8 +162,8 @@ true - - :/icons/hand.xpm:/icons/hand.xpm + + :/cgal/icons/hand.xpm:/cgal/icons/hand.xpm Drag @@ -170,8 +174,8 @@ true - - :/icons/demo_pointlocation.xpm:/icons/demo_pointlocation.xpm + + :/cgal/icons/pointlocation.xpm:/cgal/icons/pointlocation.xpm Point Location @@ -182,8 +186,8 @@ true - - :/icons/demo_rayshoot_up.xpm:/icons/demo_rayshoot_up.xpm + + :/cgal/icons/rayshoot_up.xpm:/cgal/icons/rayshoot_up.xpm Ray Shooting Up @@ -194,8 +198,8 @@ true - - :/icons/demo_rayshoot_down.xpm:/icons/demo_rayshoot_down.xpm + + :/cgal/icons/rayshoot_down.xpm:/cgal/icons/rayshoot_down.xpm Ray Shooting Down @@ -206,8 +210,8 @@ true - - :/icons/demo_merge.xpm:/icons/demo_merge.xpm + + :/cgal/icons/merge.xpm:/cgal/icons/merge.xpm Merge @@ -218,8 +222,8 @@ true - - :/icons/demo_split.xpm:/icons/demo_split.xpm + + :/cgal/icons/split.xpm:/cgal/icons/split.xpm Split @@ -230,23 +234,35 @@ true - - :/icons/demo_fill.xpm:/icons/demo_fill.xpm + + :/cgal/icons/fill.xpm:/cgal/icons/fill.xpm Fill - + true - - :/icons/demo_snapvertex.xpm:/icons/demo_snapvertex.xpm + + :/cgal/icons/grid.xpm:/cgal/icons/grid.xpm - Enable snapping + Show grid + + + + + true + + + + :/cgal/icons/snapvertex.xpm:/cgal/icons/snapvertex.xpm + + + Snap to arrangement @@ -254,28 +270,13 @@ true - - :/icons/demo_snapgrid.xpm:/icons/demo_snapgrid.xpm + + :/cgal/icons/snapgrid.xpm:/cgal/icons/snapgrid.xpm Snap to grid - - - Segment - - - - - Polyline - - - - - Conic - - New tab @@ -294,21 +295,13 @@ &Preferences... - - - true - - - Show &grid - - true - - :/icons/lower_env_xpm.xpm:/icons/lower_env_xpm.xpm + + :/cgal/icons/lower_env_xpm.xpm:/cgal/icons/lower_env_xpm.xpm Lower envelope @@ -319,72 +312,141 @@ true - - :/icons/upper_env_xpm.xpm:/icons/upper_env_xpm.xpm + + :/cgal/icons/upper_env_xpm.xpm:/cgal/icons/upper_env_xpm.xpm Upper envelope - + true - - :/icons/demo_conic_segment.xpm:/icons/demo_conic_segment.xpm + + :/cgal/icons/conic_segment.xpm:/cgal/icons/conic_segment.xpm Segment + + Segment + - + true - - :/icons/demo_conic_circle.xpm:/icons/demo_conic_circle.xpm + + :/cgal/icons/conic_segment.xpm:/cgal/icons/conic_segment.xpm + + + Polyline + + + Polyline + + + + + true + + + + :/cgal/icons/conic_circle.xpm:/cgal/icons/conic_circle.xpm Circle + + Circle + - + true - - :/icons/demo_conic_ellipse.xpm:/icons/demo_conic_ellipse.xpm + + :/cgal/icons/conic_ellipse.xpm:/cgal/icons/conic_ellipse.xpm Ellipse + + Ellipse + true - - :/icons/demo_conic_3points.xpm:/icons/demo_conic_3points.xpm + + :/cgal/icons/conic_3points.xpm:/cgal/icons/conic_3points.xpm Three Point Conic + + Three Point Conic + true - - :/icons/demo_conic_5points.xpm:/icons/demo_conic_5points.xpm + + :/cgal/icons/conic_5points.xpm:/cgal/icons/conic_5points.xpm Five Point Conic + + Five Point Conic + + + + + true + + + + :/cgal/icons/conic_segment.xpm:/cgal/icons/conic_segment.xpm + + + Bezier + + + Bezier + + + + + Add Curve + + + Curve Equation + + + + :/cgal/icons/equation.xpm:/cgal/icons/equation.xpm + + + + + Add Curve + + + Curve Equation + + + + :/cgal/icons/equation.xpm:/cgal/icons/equation.xpm + @@ -417,45 +479,69 @@ - - :/icons/demo_zoomin.xpm:/icons/demo_zoomin.xpm + + :/cgal/icons/zoomin.xpm:/cgal/icons/zoomin.xpm Zoom In + + Zoom In + - - :/icons/demo_zoomout.xpm:/icons/demo_zoomout.xpm + + :/cgal/icons/zoomout.xpm:/cgal/icons/zoomout.xpm Zoom Out + + Zoom Out + - + + + + :/cgal/icons/zoomreset.xpm:/cgal/icons/zoomreset.xpm + + + Zoom Reset + + + Zoom Reset + + + true - - :/icons/demo_conic_ray.xpm:/icons/demo_conic_ray.xpm + + :/cgal/icons/conic_ray.xpm:/cgal/icons/conic_ray.xpm Ray + + Ray + - + true - - :/icons/demo_conic_line.xpm:/icons/demo_conic_line.xpm + + :/cgal/icons/conic_line.xpm:/cgal/icons/conic_line.xpm Line + + Line + @@ -467,7 +553,7 @@ - + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp index 2ab02f6f2d2..4ad1ba51251 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.cpp @@ -1,104 +1,1076 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2008, 2012, 2020 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // -// $URL$ -// $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementGraphicsItem.h" +#include "ArrangementGraphicsItemTyped.h" +#include "ArrangementPainterOstream.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "PointsGraphicsItem.h" +#include "Utils/ConstructBoundingBox.h" +#include "Utils/PointLocationFunctions.h" + +#include +#include +#include +#include namespace CGAL { namespace Qt { -ArrangementGraphicsItemBase::ArrangementGraphicsItemBase( ) : - bb( 0, 0, 0, 0 ), - bb_initialized( false ), - verticesPen( QPen( ::Qt::blue, 3. ) ), - edgesPen( QPen( ::Qt::blue, 1. ) ), - visible_edges( true ), - visible_vertices( true ), - scene( NULL ), - backgroundColor( ::Qt::white ) +static constexpr int margin = 2; + +ArrangementGraphicsItemBase::ArrangementGraphicsItemBase() : + verticesPen(QPen(::Qt::blue, 3.)), edgesPen(QPen(::Qt::blue, 1.)) { - this->verticesPen.setCosmetic( true ); - this->verticesPen.setCapStyle( ::Qt::SquareCap ); - this->edgesPen.setCosmetic( true ); + this->verticesPen.setCosmetic(true); + this->edgesPen.setCosmetic(true); + this->edgesPen.setWidth(2); + this->facesPen.setCosmetic(true); + this->facesPen.setColor(::Qt::transparent); } -const QPen& ArrangementGraphicsItemBase::getVerticesPen( ) const +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + agi = new ArrangementGraphicsItem(arr); + } + + ArrangementGraphicsItemBase*& agi; + CGAL::Object& arr_obj; +}; +} // anonymous namespace + +ArrangementGraphicsItemBase* ArrangementGraphicsItemBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj) +{ + ArrangementGraphicsItemBase* agi; + ExplicitLambda explicit_lambda{agi, arr_obj}; + demo_types::visitArrangementType(tt, explicit_lambda); + return agi; +} + +const QPen& ArrangementGraphicsItemBase::getVerticesPen() const { return this->verticesPen; } -const QPen& ArrangementGraphicsItemBase::getEdgesPen( ) const +const QPen& ArrangementGraphicsItemBase::getEdgesPen() const { return this->edgesPen; } -void ArrangementGraphicsItemBase::setVerticesPen( const QPen& pen ) +void ArrangementGraphicsItemBase::setVerticesPen(const QPen& pen) { this->verticesPen = pen; } -void ArrangementGraphicsItemBase::setEdgesPen( const QPen& pen ) +void ArrangementGraphicsItemBase::setEdgesPen(const QPen& pen) { this->edgesPen = pen; } -bool ArrangementGraphicsItemBase::visibleVertices( ) const +template +ArrangementGraphicsItem::ArrangementGraphicsItem(Arrangement* arr_) : + arr(arr_), pointsGraphicsItem(new PointsGraphicsItem(this)) { - return this->visible_vertices; + this->updatePointsItem(); + this->updateBoundingBox(); } -void ArrangementGraphicsItemBase::setVisibleVertices( const bool b ) +template < typename Arr_ > +QRectF +ArrangementGraphicsItem< Arr_ >:: +boundingRect( ) const { - this->visible_vertices = b; - this->update( ); -} - -bool ArrangementGraphicsItemBase::visibleEdges( ) const -{ - return this->visible_edges; -} - -void ArrangementGraphicsItemBase::setVisibleEdges( const bool b ) -{ - this->visible_edges = b; - this->update( ); -} - -void ArrangementGraphicsItemBase::setBackgroundColor( QColor color ) -{ - this->backgroundColor = color; -} - -#if 0 -void ArrangementGraphicsItemBase::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; -} - -QRectF ArrangementGraphicsItemBase::getViewportRect( ) const -{ - QRectF clipRect; - if ( this->scene == NULL || this->scene->views( ).size( ) == 0 ) + qreal xmin = -(std::numeric_limits::max)() / 4; + qreal ymin = -(std::numeric_limits::max)() / 4; + qreal xmax = (std::numeric_limits::max)() / 4; + qreal ymax = (std::numeric_limits::max)() / 4; + if (this->bb.xmin() > xmin) xmin = this->bb.xmin(); + if (this->bb.ymin() > ymin) ymin = this->bb.ymin(); + if (this->bb.xmax() < xmax) xmax = this->bb.xmax(); + if (this->bb.ymax() < ymax) ymax = this->bb.ymax(); + if (xmin > xmax || ymin > ymax) { - return clipRect; + xmin = 0; + xmax = 0; + ymin = 0; + ymax = 0; + } + return {QPointF{xmin, ymin}, QPointF{xmax, ymax}}; +} + +template < typename Arr_ > +void +ArrangementGraphicsItem< Arr_ >:: +paint(QPainter* painter, + const QStyleOptionGraphicsItem* /* option */, + QWidget* /*widget*/) +{ + this->paint(painter, *(arr->traits())); +} + +template +template +void ArrangementGraphicsItem::paint( + QPainter* painter, const TTraits& traits) +{ + this->paintFaces(painter); + this->paintEdges(painter, traits); +} + +template +template +void ArrangementGraphicsItem::paint( + QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2& traits) +{ + this->paintWithFloodFill(painter, traits); +} + +template +template +void ArrangementGraphicsItem::paint( + QPainter* painter, + const CGAL::Arr_rational_function_traits_2& traits) +{ + this->paintWithFloodFill(painter, traits); +} + +template +template +void ArrangementGraphicsItem::paintWithFloodFill( + QPainter* painter, const TTraits& traits) +{ + auto windowRect = painter->window(); + auto width = windowRect.width(); + auto height = windowRect.height(); + if (tempImage.width() != width || tempImage.height() != height) + tempImage = {width, height, QImage::Format_ARGB32}; + + QRgb* st = reinterpret_cast(tempImage.bits()); + // Transparent (0) is used as a flag for an invalid color + std::fill(st, st + width * height, 0); + // draw margins with white + // prevents the flood algorithm from going over the border + // also useful with algebraic curves as sometimes pixels on the borders + // aren't painted, and the flood algorithm 'leaks' + static constexpr QRgb white = 0xFFFFFFFF; + for (uint16_t i = 0; i < margin; i++) + { + for (uint16_t j = 0; j < width; j++) + { + st[i * width + j] = white; + st[(height - 1 - i) * width + j] = white; + } + for (uint16_t j = 0; j < height; j++) + { + st[j * width + i] = white; + st[j * width + (width - 1 - i)] = white; + } } - QGraphicsView* view = this->scene->views( ).first( ); - QPointF p1 = view->mapToScene( 0, 0 ); - QPointF p2 = view->mapToScene( view->width( ), view->height( ) ); - clipRect = QRectF( p1, p2 ); + QPainter painter2{&tempImage}; + painter2.setTransform(painter->transform()); + painter2.setPen(this->edgesPen); - return clipRect; + // paint bounded faces normally? + // by experimenting it's faster to just paint all using the flood algo + // specially with algebraic faces since currenlty all edges have to + // be recalculated/rendered again for faces + // this->paintFaces(&painter2); + this->paintEdges(&painter2, traits); + // paint remaining faces using floodfill + this->paintFacesFloodFill(&painter2, tempImage); + + auto& painterTransform = painter->transform(); + painter->resetTransform(); + painter->drawImage(QPoint{0, 0}, tempImage); + painter->setTransform(painterTransform); } -#endif +template +template +void ArrangementGraphicsItem::paintEdges( + QPainter* painter, const TTraits&) +{ + auto painterOstream = + ArrangementPainterOstream(painter, this->boundingRect()); -} // namespace Qt + painterOstream.setScene(this->getScene()); + painter->setPen(this->edgesPen); + painter->setBrush(::Qt::transparent); + + for (auto it = this->arr->edges_begin(); it != this->arr->edges_end(); ++it) + { + X_monotone_curve_2 curve = it->curve(); + painterOstream << curve; + } +} + +template +template +void ArrangementGraphicsItem::paintEdges( + QPainter* painter, const CGAL::Arr_algebraic_segment_traits_2&) +{ + using TTraits = CGAL::Arr_algebraic_segment_traits_2; + + auto painterOstream = + ArrangementPainterOstream(painter, this->boundingRect()); + + painterOstream.setScene(this->getScene()); + painter->setPen(this->edgesPen); + painter->setBrush(::Qt::transparent); + + painterOstream.paintEdges(arr->edges_begin(), arr->edges_end()); +} + +template +void ArrangementGraphicsItem::paintFacesFloodFill( + QPainter* painter, QImage& image) +{ + static constexpr QRgb invalid_rgb = 0; + + QRgb* raw_img = reinterpret_cast(image.bits()); + uint16_t width = image.width(); + uint16_t height = image.height(); + + QTransform deviceToScene = painter->deviceTransform().inverted(); + + PointLocationFunctions point_location_functions; + auto get_face = [&](auto x, auto y) { + QPointF point = + deviceToScene.map(QPointF{static_cast(x), static_cast(y)}); + return point_location_functions.getFace(this->arr, point); + }; + + auto paint_face = [this, raw_img, width, get_face](auto x, auto y) { + auto face = get_face(x, y); + QRgb color = face->color().rgb(); + this->flood_fill(raw_img, width, x, y, color); + }; + + static constexpr int tot_margin = margin + 2; + auto cur_img_line = raw_img + tot_margin * width; + for (uint16_t y = tot_margin; y + 1 + tot_margin < height; y++) + { + for (uint16_t x = tot_margin; x + 1 + tot_margin < width; x++) + { + // just to account for rendering errors + // make sure the pixel falls in the right face + if ( + cur_img_line[x] == invalid_rgb && + cur_img_line[x + 1] == invalid_rgb && + cur_img_line[x - 1] == invalid_rgb && + cur_img_line[x + 2] == invalid_rgb && + cur_img_line[x - 2] == invalid_rgb && + cur_img_line[width + x] == invalid_rgb && + cur_img_line[-width + x] == invalid_rgb && + cur_img_line[2 * width + x] == invalid_rgb && + cur_img_line[- 2 * width + x] == invalid_rgb && + cur_img_line[width + x + 1] == invalid_rgb && + cur_img_line[width + x - 1] == invalid_rgb && + cur_img_line[-width + x + 1] == invalid_rgb && + cur_img_line[-width + x - 1] == invalid_rgb && + cur_img_line[width + x + 2] == invalid_rgb && + cur_img_line[width + x - 2] == invalid_rgb && + cur_img_line[-width + x + 2] == invalid_rgb && + cur_img_line[-width + x - 2] == invalid_rgb && + cur_img_line[2 * width + x + 1] == invalid_rgb && + cur_img_line[2 * width + x - 1] == invalid_rgb && + cur_img_line[-2 * width + x + 1] == invalid_rgb && + cur_img_line[-2 * width + x - 1] == invalid_rgb && + cur_img_line[2 * width + x + 2] == invalid_rgb && + cur_img_line[2 * width + x - 2] == invalid_rgb && + cur_img_line[-2 * width + x + 2] == invalid_rgb && + cur_img_line[-2 * width + x - 2] == invalid_rgb) + paint_face(x, y); + } + cur_img_line += width; + } +} + +template < typename Arr_ > +void ArrangementGraphicsItem< Arr_ >::updateBoundingBox( ) +{ + this->prepareGeometryChange(); + + this->bb = {}; + ConstructBoundingBox construct_bounding_box; + for (auto it = this->arr->edges_begin(); it != this->arr->edges_end(); ++it) + this->bb += construct_bounding_box(it->curve()); + + for (auto it = this->arr->vertices_begin(); it != this->arr->vertices_end(); + ++it) + this->bb += construct_bounding_box(it->point()); +} + +template +void ArrangementGraphicsItem::updatePointsItem() +{ + this->pointsGraphicsItem->clear(); + for (auto it = this->arr->vertices_begin(); it != this->arr->vertices_end(); + ++it) + { + Point_2 p = it->point(); + this->pointsGraphicsItem->insert(p); + } +} + +template < typename Arr_ > +void ArrangementGraphicsItem< Arr_ >::modelChanged( ) +{ + this->updatePointsItem(); + this->updateBoundingBox( ); + this->update( ); +} + +template < typename Arr_ > +void +ArrangementGraphicsItem< Arr_ >:: +paintFace( Face_handle f, QPainter* painter ) +{ + if (f->visited()) return; + + Hole_iterator hit; // holes iterator + this->paintFace(f, painter, *(arr->traits())); + f->set_visited(true); + + for (hit = f->holes_begin(); hit != f->holes_end(); ++hit) + { + // Traverse in clockwise order + Ccb_halfedge_circulator cc = *hit; + do + { + Halfedge_handle he = cc; + Halfedge_handle he2 = he->twin(); + Face_handle inner_face = he2->face(); + if (this->antenna(he)) continue; + + this->visit_ccb_faces(inner_face, painter); + } while (++cc != *hit); + } +} + +template +template +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, const CGAL::Arr_segment_traits_2&) +{ + if (!f->is_unbounded()) // f is not the unbounded face + { + QVector< QPointF > pts; // holds the points of the polygon + + /* running with around the outer of the face and generate from it + * polygon + */ + Ccb_halfedge_circulator cc=f->outer_ccb(); + do { + double x = CGAL::to_double(cc->source()->point().x()); + double y = CGAL::to_double(cc->source()->point().y()); + QPointF coord_source(x , y); + pts.push_back(coord_source ); + //created from the outer boundary of the face + } while (++cc != f->outer_ccb()); + + // make polygon from the outer ccb of the face 'f' + QPolygonF pgn (pts); + + QColor color = f->color(); + painter->setBrush(color); + painter->drawPolygon( pgn ); + } + else + { + QRectF rect = this->viewportRect( ); + QColor color = f->color(); + painter->fillRect(rect, color); + } +} + +template +template +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, const CGAL::Arr_polyline_traits_2&) +{ + if (!f->is_unbounded()) + { + QVector< QPointF > pts; // holds the points of the polygon + + CGAL::Qt::Converter convert; + /* running with around the outer of the face and generate from it + * polygon + */ + Ccb_halfedge_circulator cc = f->outer_ccb(); + do { + if (this->antenna(cc)) continue; + + QPointF src = convert(cc->source()->point()); + QPointF tgt = convert(cc->target()->point()); + + Halfedge he = *cc; + if (he.direction() == ARR_LEFT_TO_RIGHT && src.x() > tgt.x()) + std::swap(src, tgt); + else if (he.direction() == ARR_RIGHT_TO_LEFT && src.x() < tgt.x()) + std::swap(src, tgt); + + auto&& curve = cc->curve(); + auto first_subcurve = curve.subcurves_begin(); + QPointF src_first = convert(first_subcurve->source()); + + if (src_first == src) + { + for (auto it = curve.subcurves_begin(); it != curve.subcurves_end(); + ++it) + { + pts.push_back(convert(it->source())); + pts.push_back(convert(it->target())); + } + } + else + { + QVector pts_tmp; + for (auto it = curve.subcurves_begin(); it != curve.subcurves_end(); + ++it) + { + pts_tmp.push_front(convert(it->source())); + pts_tmp.push_front(convert(it->target())); + } + pts += pts_tmp; + } + } while (++cc != f->outer_ccb()); + + // make polygon from the outer ccb of the face 'f' + QPolygonF pgn( pts ); + + painter->setBrush(f->color()); + painter->drawPolygon( pgn ); + } + else + { + QRectF rect = this->viewportRect( ); + QColor color = f->color(); + painter->fillRect(rect, color); + } +} + +template +template +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2& /* traits */) +{ + if (f->is_unbounded()) return; + + ArrangementPainterOstream painterOstream{ + painter, this->boundingRect()}; + painterOstream.setScene(this->getScene()); + + painter->save(); + painter->setTransform(painterOstream.getPointsListMapping()); + + QVector pts; + /* running with around the outer of the face and generate from it + * polygon + */ + Ccb_halfedge_circulator cc = f->outer_ccb(); + do + { + if (this->antenna(cc)) continue; + + auto points = painterOstream.getPointsList(cc->curve()); + if (points.empty()) continue; + + double src_x = CGAL::to_double(cc->source()->point().x()); + double tgt_x = CGAL::to_double(cc->target()->point().x()); + + if (src_x < tgt_x) + { + for (auto& vec : points) + for(auto& vit : vec) + pts.push_back({vit.first, vit.second}); + } + else + { + for (auto vecit = points.rbegin(); vecit != points.rend(); ++vecit) + for (auto vit = vecit->rbegin(); vit != vecit->rend(); ++vit) + pts.push_back({vit->first, vit->second}); + } + } while (++cc != f->outer_ccb()); + + // make polygon from the outer ccb of the face 'f' + QPolygonF pgn(pts); + painter->setBrush(f->color()); + painter->drawPolygon(pgn); + + painter->restore(); +} + +template +void ArrangementGraphicsItem::paintFaces(QPainter* painter) +{ + QPen pen = painter->pen(); + painter->setPen(this->facesPen); + + // Prepare all faces for painting + for (auto fi = this->arr->faces_begin(); fi != this->arr->faces_end(); ++fi) + fi->set_visited(false); + + for (auto fi = this->arr->faces_begin(); fi != this->arr->faces_end(); ++fi) + this->paintFace(fi, painter); + + painter->setPen(pen); +} + +template +void ArrangementGraphicsItem::visit_ccb_faces( + Face_handle& fh, QPainter* painter) +{ + this->paintFace(fh, painter); + + Ccb_halfedge_circulator cc = fh->outer_ccb(); + do + { + Halfedge he = *cc; + if (!he.twin()->face()->visited()) + { + Face_handle nei = he.twin()->face(); + this->visit_ccb_faces(nei, painter); + } + // created from the outer boundary of the face + } while (++cc != fh->outer_ccb()); +} + +template +bool ArrangementGraphicsItem::antenna(Halfedge_handle h) +{ + Halfedge_handle twin = h->twin(); + return (twin->face() == h->face()); +} + +template +template +void ArrangementGraphicsItem::paintFace(Face_handle, QPainter*, ArrTraits) +{ +} + +template +template +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_conic_traits_2&) +{ + if (!f->is_unbounded()) // f is not the unbounded face + { + QVector pts; // holds the points of the polygon + /* running with around the outer of the face and generate from it + * polygon + */ + Ccb_halfedge_circulator cc = f->outer_ccb(); + do + { + if (this->antenna(cc)) { continue; } + + Halfedge_handle he = cc; + X_monotone_curve_2 c = he->curve(); + // Get the co-ordinates of the curve's source and target. + double sx = CGAL::to_double(he->source()->point().x()), + sy = CGAL::to_double(he->source()->point().y()), + tx = CGAL::to_double(he->target()->point().x()), + ty = CGAL::to_double(he->target()->point().y()); + + QPointF coord_source(sx, sy); + QPointF coord_target(tx, ty); + + // Transform the point coordinates from general coordinate system to + // Qt scene coordinate system + QPoint coord_source_viewport = this->fromScene(coord_source); + QPoint coord_target_viewport = this->fromScene(coord_target); + + if (c.orientation() == CGAL::COLLINEAR) { pts.push_back(coord_source); } + else + { + // If the curve is monotone, than its source and its target has the + // extreme x co-ordinates on this curve. + bool is_source_left = (sx < tx); + int x_min = is_source_left ? coord_source_viewport.x() + : coord_target_viewport.x(); + int x_max = is_source_left ? coord_target_viewport.x() + : coord_source_viewport.x(); + + pts.push_back(coord_source); + + // Draw the curve as pieces of small segments + const int DRAW_FACTOR = 5; + int start; + int end; + int step; + if (is_source_left) + { + start = x_min + DRAW_FACTOR; + end = x_max; + step = DRAW_FACTOR; + } + else + { + start = x_max; + end = x_min; + step = -DRAW_FACTOR; + } + for (int x = start; x < end; x += step) + { + double curr_x = this->toScene(QPoint{x, 0}).x(); + AlgKernel ker; + Point_2 curr_p(curr_x, 0); + + // If curr_x > x_max or curr_x < x_min + if (!(ker.compare_x_2_object()(curr_p, c.left()) != CGAL::SMALLER && + ker.compare_x_2_object()(curr_p, c.right()) != CGAL::LARGER)) + { continue; } + + auto px = c.point_at_x(curr_p); + double curr_y = CGAL::to_double(px.y()); + QPointF curr(curr_x, curr_y); + pts.push_back(curr); + } + pts.push_back(coord_target); + } + } while (++cc != f->outer_ccb()); + + QPolygonF pgn(pts); + painter->setBrush(f->color()); + painter->drawPolygon(pgn); + } + else + { + QRectF rect = this->viewportRect(); + QColor color = f->color(); + painter->fillRect(rect, color); + } +} + +template +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits>&) +{ + if (!f->is_unbounded()) + { + ArrangementPainterOstream painterOstream{ + painter, this->boundingRect()}; + painterOstream.setScene(this->getScene()); + + QVector pts; + Ccb_halfedge_circulator cc = f->outer_ccb(); + do + { + if (this->antenna(cc)) continue; + + const X_monotone_curve_2& curve = cc->curve(); + auto points = painterOstream.getPoints(curve); + + if (cc->source()->point().is_same(curve.source())) + for (auto& vit : points) + pts.push_back({vit.first, vit.second}); + else + for (auto it = points.rbegin(); it != points.rend(); ++it) + pts.push_back({it->first, it->second}); + + } while(++cc != f->outer_ccb()); + + QPolygonF pgn(pts); + QColor color = f->color(); + painter->setBrush(color); + painter->drawPolygon(pgn); + } + else + { + QRectF rect = this->viewportRect(); + QColor color = f->color(); + painter->fillRect(rect, color); + } +} + +template +template +void ArrangementGraphicsItem::paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_linear_traits_2& /* traits */) +{ + QVector pts; // holds the points of the polygon + QColor color = f->color(); + painter->setBrush(color); + if (!f->is_unbounded()) + { + /* running with around the outer of the face and generate from it + * polygon + */ + Ccb_halfedge_circulator cc = f->outer_ccb(); + do + { + Halfedge_handle hh = cc; + if (this->antenna(hh)) continue; + + double x = CGAL::to_double(cc->source()->point().x()); + double y = CGAL::to_double(cc->source()->point().y()); + QPointF coord_source(x, y); + pts.push_back(coord_source); + } while (++cc != f->outer_ccb()); + + painter->drawPolygon(QPolygonF{pts}); + } + else + { + std::vector halfedges; + Ccb_halfedge_circulator cc = f->outer_ccb(); + do + { + Halfedge_handle hh = cc; + if (cc->is_fictitious() || this->antenna(hh)) + continue; + + halfedges.push_back(hh); + } while (++cc != f->outer_ccb()); + + QRectF rect = this->viewportRect(); + + switch (halfedges.size()) + { + // one unbounded face + case 0: { + painter->fillRect(rect, color); + break; + } + // two unbounded faces + case 1: { + auto&& curve = halfedges.front()->curve(); + auto&& line = curve.line(); + + // horizontal or mostly horizontal + if (CGAL::abs(line.b()) > CGAL::abs(line.a())) + { + qreal left_y = CGAL::to_double(line.y_at_x(rect.left())); + qreal right_y = CGAL::to_double(line.y_at_x(rect.right())); + + pts.push_back({rect.left(), left_y}); + pts.push_back({rect.right(), right_y}); + if (cc->direction() == ARR_LEFT_TO_RIGHT) + { + pts.push_back(rect.bottomRight()); + pts.push_back(rect.bottomLeft()); + } + else + { + pts.push_back(rect.topRight()); + pts.push_back(rect.topLeft()); + } + } + // vertical or mostly vertical + else + { + qreal top_x = CGAL::to_double(line.x_at_y(rect.top())); + qreal bottom_x = CGAL::to_double(line.x_at_y(rect.bottom())); + + pts.push_back({top_x, rect.top()}); + pts.push_back({bottom_x, rect.bottom()}); + if (cc->direction() == ARR_LEFT_TO_RIGHT) + { + pts.push_back(rect.bottomLeft()); + pts.push_back(rect.topLeft()); + } + else + { + pts.push_back(rect.bottomRight()); + pts.push_back(rect.topRight()); + } + } + + painter->drawPolygon(QPolygonF{pts}); + break; + } + // general case + default: { + using Vertex_handle = typename Arrangement::Vertex_handle; + + auto handle_vertex = [&](Halfedge_handle halfedge, Vertex_handle vertex) + { + // dx * y = dy * x + c + typename Kernel_::RT dx, dy, c; + + auto&& curve = halfedge->curve(); + if (curve.is_segment()) + { + auto&& src = halfedge->source()->point(); + auto&& tgt = halfedge->target()->point(); + dy = tgt.y() - src.y(); + dx = tgt.x() - src.x(); + c = dx * src.y() - dy * src.x(); + } + else if(curve.is_ray()) + { + auto&& ray = curve.ray(); + auto&& dir = ray.direction(); + auto&& src = ray.source(); + dy = dir.dy(); + dx = dir.dx(); + c = dx * src.y() - dy * src.x(); + } + // halfedge can be a line in case of a face between two parallel lines + else + { + auto&& line = curve.line(); + auto param_in_x = vertex->parameter_space_in_x(); + auto param_in_y = vertex->parameter_space_in_y(); + dy = line.a(); + dx = -line.b(); + c = line.c(); + + if ( + (param_in_x == LEFT_BOUNDARY && CGAL::is_positive(dx)) || + (param_in_x == RIGHT_BOUNDARY && CGAL::is_negative(dx)) || + (param_in_y == BOTTOM_BOUNDARY && CGAL::is_positive(dy)) || + (param_in_y == TOP_BOUNDARY && CGAL::is_negative(dy))) + { + dx = -dx; + dy = -dy; + c = -c; + } + } + // horizontal or mostly horizontal + if (CGAL::abs(dx) > CGAL::abs(dy)) + { + qreal x = CGAL::is_positive(dx) ? rect.right() + rect.width() + : rect.left() - rect.width(); + // in case vertex is a finite point + if (!vertex->is_at_open_boundary()) + { + auto p = vertex->point(); + // check not far away + if ( + (CGAL::is_positive(dx) && p.x() < x) || + (CGAL::is_negative(dx) && p.x() > x)) + { + pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); + return; + } + } + // in case vertex is far away (finite or at infinity), get a nearer + // point on the line + // i.e. in case farther than twice the width of the viewport + qreal y = CGAL::to_double((dy / dx) * x + (c / dx)); + pts.push_back({x, y}); + } + // vertical or mostly vertical + else + { + qreal y = CGAL::is_positive(dy) ? rect.bottom() + rect.height() + : rect.top() - rect.height(); + // in case vertex is a finite point + if (!vertex->is_at_open_boundary()) + { + auto p = vertex->point(); + // check not far away + if ( + (CGAL::is_positive(dy) && p.y() < y) || + (CGAL::is_negative(dy) && p.y() > y)) + { + pts.push_back({CGAL::to_double(p.x()), CGAL::to_double(p.y())}); + return; + } + } + // in case vertex is far away (finite or at infinity), get a nearer + // point on the line + // i.e. in case farther than twice the height of the viewport + qreal x = CGAL::to_double((dx / dy) * y - (c / dy)); + pts.push_back({x, y}); + } + }; + + for (auto hh : halfedges) + { + handle_vertex(hh, hh->source()); + handle_vertex(hh, hh->target()); + } + + painter->drawPolygon(QPolygonF{pts}); + break; + } + } + } +} + +// TODO: clean all this portion up (move it somewhere?), it's ugly! +static CGAL::Bbox_2 reject_not_in_allowable_range( + const CGAL::Bbox_2& box, const CGAL::Bbox_2& allowable_range) +{ + double xmin = std::numeric_limits::infinity(); + double ymin = std::numeric_limits::infinity(); + double xmax = -std::numeric_limits::infinity(); + double ymax = -std::numeric_limits::infinity(); + + if (box.xmin() > allowable_range.xmin()) xmin = box.xmin(); + if (box.ymin() > allowable_range.ymin()) ymin = box.ymin(); + if (box.xmax() < allowable_range.xmax()) xmax = box.xmax(); + if (box.ymax() < allowable_range.ymax()) ymax = box.ymax(); + return {xmin, ymin, xmax, ymax}; +} + +static bool isFinite(const CGAL::Bbox_2& box) +{ + return !std::isinf(box.xmin()) && !std::isinf(box.xmax()) && + !std::isinf(box.ymin()) && !std::isinf(box.ymax()); +} + +static CGAL::Bbox_2 addMargins(const CGAL::Bbox_2& box) +{ + // add margin to bounding box + double x_margin; + double y_margin; + if (box.xmin() == box.xmax() || box.ymin() == box.ymax()) + { + static constexpr float const_margin = 50; + x_margin = const_margin; + y_margin = const_margin; + } + else + { + static constexpr double prop_margin = 0.10; + x_margin = (box.xmax() - box.xmin()) * prop_margin; + y_margin = (box.ymax() - box.ymin()) * prop_margin; + } + return { + box.xmin() - x_margin, box.ymin() - y_margin, box.xmax() + x_margin, + box.ymax() + y_margin}; +} + +template +CGAL::Bbox_2 +findOtherInterestingPoints(const Arr_*, const CGAL::Bbox_2&) +{ + return {}; +} + +#ifdef CGAL_USE_CORE +template +static const auto& +getXyCurves(const CGAL::Arr_algebraic_segment_traits_2* traits) +{ + // the traits object is only needed the first time + // this assumes that X_monotone_curves created from the first traits object + // will work with arrangements with a different object + using Traits = CGAL::Arr_algebraic_segment_traits_2; + static std::vector xy_curves; + if (xy_curves.empty()) + { + typedef typename Traits::Polynomial_2 Polynomial_2; + auto construct_curve = traits->construct_curve_2_object(); + auto make_x_monotone = traits->make_x_monotone_2_object(); + + Polynomial_2 x = CGAL::shift(Polynomial_2(1), 1, 0); + Polynomial_2 y = CGAL::shift(Polynomial_2(1), 1, 1); + auto x_cv = construct_curve(x); + auto y_cv = construct_curve(y); + + std::vector arcs; + make_x_monotone(x_cv, std::back_inserter(arcs)); + make_x_monotone(y_cv, std::back_inserter(arcs)); + for (auto& arc_obj : arcs) + { + typename Traits::X_monotone_curve_2 arc; + CGAL::assign(arc, arc_obj); + xy_curves.push_back(arc); + } + } + return xy_curves; +} + +template <> +CGAL::Bbox_2 findOtherInterestingPoints( + const demo_types::DemoTypes::Alg_seg_arr* arr, + const CGAL::Bbox_2& allowable_range) +{ + using Traits = demo_types::DemoTypes::Alg_seg_traits; + CGAL::Bbox_2 bb = {}; + std::vector intersections; + for (auto it = arr->edges_begin(); it != arr->edges_end(); ++it) + { + for (auto& arc : getXyCurves(arr->traits())) + if (arc.is_vertical() != it->curve().is_vertical()) + it->curve().intersections(arc, std::back_inserter(intersections)); + } + for (auto it = intersections.begin(); it != intersections.end(); it++) + { + std::pair point_multiplicity; + CGAL::assign(point_multiplicity, *it); + auto& point = point_multiplicity.first; + if (point.location() == CGAL::ARR_INTERIOR) + { + auto xy = point.to_double(); + bb += reject_not_in_allowable_range( + {xy.first, xy.second, xy.first, xy.second}, allowable_range); + } + } + return bb; +} +#endif // CGAL_USE_CORE + + +template +QRectF ArrangementGraphicsItem::getInterestingViewport() const +{ + QRectF scene_rect = this->getScene()->sceneRect(); + CGAL::Bbox_2 scene_bbox = { + scene_rect.left(), scene_rect.top(), scene_rect.right(), + scene_rect.bottom()}; + + ConstructBoundingBox construct_bounding_box; + CGAL::Bbox_2 bounding_box = {}; + for (auto it = this->arr->edges_begin(); + it != this->arr->edges_end(); ++it) + { + bounding_box += reject_not_in_allowable_range( + construct_bounding_box(it->curve()), scene_bbox); + } + for (auto it = this->arr->vertices_begin(); + it != this->arr->vertices_end(); ++it) + { + bounding_box += reject_not_in_allowable_range( + construct_bounding_box(it->point()), scene_bbox); + } + + if (!isFinite(bounding_box)) + bounding_box += findOtherInterestingPoints(this->arr, scene_bbox); + + // ideally this should happen only if the arrangement is empty + // (if findOtherInterestingPoints worked for all arrangement types) + if (!isFinite(bounding_box)) bounding_box += {0, 0, 0, 0}; + + bounding_box = addMargins(bounding_box); + + return QRectF( + bounding_box.xmin(), bounding_box.ymin(), + bounding_box.xmax() - bounding_box.xmin(), + bounding_box.ymax() - bounding_box.ymin()); +} + +} // namespace QT } // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.h index acc58702316..efa4db83927 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItem.h @@ -1,1300 +1,59 @@ -// Copyright (c) 2008, 2012 GeometryFactory Sarl (France). +// Copyright (c) 2008, 2012, 2020 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef CGAL_QT_ARRANGEMENT_GRAPHICS_ITEM_H #define CGAL_QT_ARRANGEMENT_GRAPHICS_ITEM_H +#include #include -//#include -// TODO: should be included in PainterOstream.h -//#include #include -#include -#include -#include -#include +#include +#include -#include -#include -//#include +#include "GraphicsSceneMixin.h" -#include "ArrangementPainterOstream.h" -#include "Utils.h" -#include -#ifdef _MSC_VER -#define _USE_MATH_DEFINES -#endif -#include +namespace demo_types +{ +enum class TraitsType : int; +} -class QGraphicsScene; - -namespace CGAL { -namespace Qt { +namespace CGAL +{ +namespace Qt +{ class ArrangementGraphicsItemBase : - public GraphicsItem, public QGraphicsSceneMixin + public GraphicsItem, + public GraphicsSceneMixin { public: - ArrangementGraphicsItemBase( ); + static ArrangementGraphicsItemBase* + create(demo_types::TraitsType, CGAL::Object arr); - const QPen& getVerticesPen( ) const; - const QPen& getEdgesPen( ) const; - void setVerticesPen( const QPen& pen ); - void setEdgesPen( const QPen& pen ); - bool visibleVertices( ) const; - void setVisibleVertices( const bool b ); - bool visibleEdges( ) const; - void setVisibleEdges( const bool b ); - void setBackgroundColor( QColor color ); - // void setScene( QGraphicsScene* scene_ ); + const QPen& getVerticesPen() const; + const QPen& getEdgesPen() const; + void setVerticesPen(const QPen& pen); + void setEdgesPen(const QPen& pen); + void setBackgroundColor(QColor color); + + virtual QRectF getInterestingViewport() const = 0; protected: - // QRectF getViewportRect( ) const; - - CGAL::Bbox_2 bb; - bool bb_initialized; + ArrangementGraphicsItemBase(); QPen verticesPen; QPen edgesPen; - bool visible_edges; - bool visible_vertices; - - QGraphicsScene* scene; - - QColor backgroundColor; - + QPen facesPen; }; // class ArrangementGraphicsItemBase -template -class ArrangementGraphicsItem : public ArrangementGraphicsItemBase -{ - typedef Arr_ Arrangement; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Arrangement::Curve_iterator Curve_iterator; - typedef typename Arrangement::Edge_iterator Edge_iterator; - typedef typename Arrangement::Halfedge Halfedge; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Face_handle Face_handle; - typedef typename Arrangement::Face_iterator Face_iterator; - typedef typename Arrangement::Hole_iterator Holes_iterator; - typedef typename Arrangement::Ccb_halfedge_circulator Ccb_halfedge_circulator; - - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Traits::Point_2 Point_2; - //typedef typename Kernel::Segment_2 Segment_2; - - typedef ArrangementGraphicsItemBase Superclass; - typedef typename Kernel::Segment_2 Segment_2; - -public: - /*! Constructor */ - ArrangementGraphicsItem( Arrangement* t_ ); - - /*! Destructor (virtual) */ - ~ArrangementGraphicsItem() {} - -public: - void modelChanged( ); - QRectF boundingRect( ) const; - virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, - QWidget* widget); - -protected: - template < typename TTraits > - void paint( QPainter* painter, TTraits traits ); - - template < typename Kernel_ > - void paint( QPainter* painter, CGAL::Arr_linear_traits_2< Kernel_ > traits ); - - template < typename CircularKernel > - void paint( QPainter* painter, - CGAL::Arr_circular_arc_traits_2< CircularKernel > traits ); - - // template < typename Coefficient_ > - // void paint( QPainter* painter, - // CGAL::Arr_algebraic_segment_traits_2< Coefficient_ > traits ); - - - void paintFaces( QPainter* painter ) - { - typename Traits::Left_side_category category; - this->paintFaces( painter, category ); - } - - void paintFaces( QPainter* painter, CGAL::Arr_oblivious_side_tag ) - { - for( Face_iterator fi = this->arr->faces_begin( ); - fi != this->arr->faces_end( ); ++fi ) - { - fi->set_visited( false ); - } - - Face_handle unboundedFace = this->arr->unbounded_face( ); - this->paintFace( unboundedFace, painter ); - } - - void paintFaces( QPainter* painter, CGAL::Arr_open_side_tag ) - { - for( Face_iterator fi = this->arr->faces_begin( ); - fi != this->arr->faces_end( ); ++fi ) - { - // if ( fi->is_fictitious( ) ) - // { - // std::cout << "setting fictitious face not visited" << std::endl; - // } - fi->set_visited( false ); - } - - Face_handle fictitiousFace = this->arr->fictitious_face( ); - this->paintFace( fictitiousFace, painter ); - } - -#if 0 - template < typename TTraits > - void paintFaces( QPainter* painter, TTraits traits ) { } - - template < typename Kernel_ > - void paintFaces(QPainter* painter, CGAL::Arr_segment_traits_2) {} - - template < typename Kernel_ > - void paintFaces(QPainter* painter, CGAL::Arr_polyline_traits_2) {} - - template < typename RatKernel, class AlgKernel, class NtTraits > - void paintFaces(QPainter* painter, - CGAL::Arr_conic_traits_2) - {} - - template < typename CircularKernel > - void paintFaces(QPainter* painter, - CGAL::Arr_circular_arc_traits_2 traits) {} - - template < typename Coefficient_ > - void paintFaces(QPainter* painter, - CGAL::Arr_algebraic_segment_traits_2 traits) {} -#endif - - void paintFace( Face_handle f, QPainter* painter ) - { - if (! f->visited( ) ) - { - int holes = 0; - int inner_faces = 0; - Holes_iterator hit; // holes iterator - this->paintFace( f, painter, Traits( ) ); - f->set_visited( true ); - for ( hit = f->holes_begin(); hit != f->holes_end(); ++hit ) - { - Ccb_halfedge_circulator cc = *hit; - do { - Halfedge_handle he = cc; - Halfedge_handle he2 = he->twin(); - Face_handle inner_face = he2->face(); - if ( this->antenna( he ) ) - continue; - - // move on to next hole - if ( ! inner_face->visited( ) ) - inner_faces++; - this->visit_ccb_faces( inner_face, painter ); - } while ( ++cc != *hit ); - holes++; - }// for - // if ( f->is_unbounded( ) ) - // { - // std::cout << "unbounded face has " << holes << " holes" << std::endl; - // std::cout << "unbounded face has " << inner_faces << " inner faces" - // << std::endl; - // } - // if ( f->is_fictitious( ) ) - // { - // std::cout << "fictitious face has " << holes << " holes" - // << std::endl; - // std::cout << "fictitious face has " << inner_faces << " inner faces" - // << std::endl; - // } - } - } - - void visit_ccb_faces( Face_handle & fh, QPainter* painter ) - { - this->paintFace( fh, painter ); - - Ccb_halfedge_circulator cc=fh->outer_ccb(); - do { - Halfedge he = *cc; - if (! he.twin()->face()->visited()) - { - Face_handle nei = (Face_handle) he.twin()->face(); - this->visit_ccb_faces( nei , painter ); - } - //created from the outer boundary of the face - } while (++cc != fh->outer_ccb()); - } - - /*! antenna - return true if the halfedge and its - * twin point to the same face. - */ - bool antenna(Halfedge_handle h) - { - Halfedge_handle twin = h->twin(); - return (twin->face() == h->face()); - } - - template < typename Traits > - void paintFace(Face_handle /* f */, QPainter* /* painter */, - Traits /* traits */) - { } - - template < typename Kernel_ > - void paintFace( Face_handle f, QPainter* painter, - CGAL::Arr_segment_traits_2< Kernel_ > ) - { - if (!f->is_unbounded()) // f is not the unbounded face - { - QVector< QPointF > pts; // holds the points of the polygon - - /* running with around the outer of the face and generate from it - * polygon - */ - Ccb_halfedge_circulator cc=f->outer_ccb(); - do { - double x = CGAL::to_double(cc->source()->point().x()); - double y = CGAL::to_double(cc->source()->point().y()); - QPointF coord_source(x , y); - pts.push_back(coord_source ); - //created from the outer boundary of the face - } while (++cc != f->outer_ccb()); - - // make polygon from the outer ccb of the face 'f' - QPolygonF pgn (pts); - - // FIXME: get the bg color - QColor color = this->backgroundColor; - if ( f->color().isValid() ) - { - color = f->color(); - } - QBrush oldBrush = painter->brush( ); - painter->setBrush( color ); - painter->drawPolygon( pgn ); - painter->setBrush( oldBrush ); - } - else - { - QRectF rect = this->viewportRect( ); - QColor color = this->backgroundColor; - painter->fillRect( rect, color ); - } - } - - template < typename Kernel_ > - void paintFace( Face_handle f, QPainter* painter, - CGAL::Arr_polyline_traits_2< Kernel_ > ) - { - if (!f->is_unbounded()) // f is not the unbounded face - { - typedef typename CGAL::Arr_polyline_traits_2 Arr_poly_traits; - typedef typename Arr_poly_traits::Compare_endpoints_xy_2 Comp_end_pts_2; - typedef typename Arr_poly_traits::Construct_min_vertex_2 Poly_const_min_v; - typedef typename Arr_poly_traits::Construct_max_vertex_2 Poly_const_max_v; - - // Obtain a polyline traits class and construct the needed functors - Arr_poly_traits poly_tr; - Comp_end_pts_2 comp_end_pts = poly_tr.compare_endpoints_xy_2_object(); - Poly_const_min_v poly_const_min_v=poly_tr.construct_min_vertex_2_object(); - Poly_const_max_v poly_const_max_v=poly_tr.construct_max_vertex_2_object(); - - // Construct needed functors from the segment traits - typedef typename Arr_poly_traits::Subcurve_traits_2 Subcurve_traits; - typedef typename Subcurve_traits::Construct_min_vertex_2 Seg_const_min_v; - typedef typename Subcurve_traits::Construct_max_vertex_2 Seg_const_max_v; - Seg_const_min_v construct_min_v = poly_tr.subcurve_traits_2()-> - construct_min_vertex_2_object(); - Seg_const_max_v construct_max_v = poly_tr.subcurve_traits_2()-> - construct_max_vertex_2_object(); - - // Iterator of the segments of an x-monotone polyline - typename X_monotone_curve_2::Subcurve_const_iterator seg_it; - - QVector< QPointF > pts; // holds the points of the polygon - X_monotone_curve_2 cv; - - /* running with around the outer of the face and generate from it - * polygon - */ - Ccb_halfedge_circulator cc = f->outer_ccb(); - do { - cv = cc->curve(); - - // Determine the direction of cv (left-to-right or right-to-left) - Comparison_result dir = comp_end_pts(cv); - - for (seg_it = cv.subcurves_begin(); - seg_it != cv.subcurves_end() ; ++seg_it) - { - if (dir == SMALLER) - { - // cv is directed from left-to-right - // Adding the left-min vertex of the current segment - double x = CGAL::to_double((construct_min_v(*seg_it)).x()); - double y = CGAL::to_double((construct_min_v(*seg_it)).y()); - QPointF coord_source(x , y); - pts.push_back(coord_source ); - } - else - { - // cv is directed from right-to-left - // Adding the right-max vertex of the current segment - double x = CGAL::to_double((construct_max_v(*seg_it)).x()); - double y = CGAL::to_double((construct_max_v(*seg_it)).y()); - QPointF coord_source(x , y); - pts.push_back(coord_source ); - } - } - - if (dir == SMALLER) - { - // Add the right-most point of cv - double x = CGAL::to_double((poly_const_max_v(cv)).x()); - double y = CGAL::to_double((poly_const_max_v(cv)).y()); - QPointF coord_source(x , y); - pts.push_back(coord_source ); - } - else - { - // Add the left-most point of cv - double x = CGAL::to_double((poly_const_min_v(cv)).x()); - double y = CGAL::to_double((poly_const_min_v(cv)).y()); - QPointF coord_source(x , y); - pts.push_back(coord_source ); - } - //created from the outer boundary of the face - } while (++cc != f->outer_ccb()); - - // make polygon from the outer ccb of the face 'f' - QPolygonF pgn( pts ); - - // fill the face according to its color (stored at any of her - // incidents curves) - QBrush oldBrush = painter->brush( ); - QColor def_bg_color = this->backgroundColor; - if (! f->color().isValid()) - { - painter->setBrush( def_bg_color ); - } - else - { - painter->setBrush( f->color( ) ); - } - painter->drawPolygon( pgn ); - painter->setBrush( oldBrush ); - } - else - { - QRectF rect = this->viewportRect( ); - QColor color = this->backgroundColor; - painter->fillRect( rect, color ); - } - } - -#ifdef CGAL_USE_CORE - template < typename RatKernel, typename AlgKernel, typename NtTraits > - void paintFace( Face_handle f, QPainter* painter, - CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > ) - { - if (! f->is_unbounded()) // f is not the unbounded face - { - QVector< QPointF > pts; // holds the points of the polygon - /* running with around the outer of the face and generate from it - * polygon - */ - Ccb_halfedge_circulator cc=f->outer_ccb(); - do - { - if (this->antenna(cc)) - continue; - - Halfedge_handle he = cc; - X_monotone_curve_2 c = he->curve(); - // Get the co-ordinates of the curve's source and target. - double sx = CGAL::to_double(he->source()->point().x()), - sy = CGAL::to_double(he->source()->point().y()), - tx = CGAL::to_double(he->target()->point().x()), - ty = CGAL::to_double(he->target()->point().y()); - - QPointF coord_source(sx, sy); - QPointF coord_target(tx, ty); - QPoint coord_source_viewport = this->fromScene( coord_source ); - QPoint coord_target_viewport = this->fromScene( coord_target ); - - if (c.orientation() == CGAL::COLLINEAR) - pts.push_back(coord_source ); - else - { - // If the curve is monotone, than its source and its target has the - // extreme x co-ordinates on this curve. - bool is_source_left = (sx < tx); - int x_min = is_source_left ? - coord_source_viewport.x( ) : coord_target_viewport.x( ); - int x_max = is_source_left ? - coord_target_viewport.x( ) : coord_source_viewport.x( ); - double curr_x, curr_y; - int x; - - Arr_conic_point_2 px; - - pts.push_back(coord_source ); - - const int DRAW_FACTOR = 5; - if (is_source_left) - { - for (x = x_min + DRAW_FACTOR; x < x_max; x+=DRAW_FACTOR) - { - //= COORD_SCALE) - curr_x = this->toScene( x ); - Alg_kernel ker; - Arr_conic_point_2 curr_p(curr_x, 0); - if (!(ker.compare_x_2_object()(curr_p, c.left()) != - CGAL::SMALLER && - ker.compare_x_2_object()(curr_p, c.right()) != - CGAL::LARGER)) - continue; - px = c.point_at_x (curr_p); - curr_y = CGAL::to_double(px.y()); - QPointF curr( curr_x, curr_y ); - pts.push_back( curr ); - }// for - } - else - { - for (x = x_max; x > x_min; x-=DRAW_FACTOR) - { - curr_x = this->toScene( x ); - Alg_kernel ker; - Arr_conic_point_2 curr_p(curr_x, 0); - if (!(ker.compare_x_2_object() (curr_p, c.left()) != - CGAL::SMALLER && - ker.compare_x_2_object() (curr_p, c.right()) != - CGAL::LARGER)) - continue; - px = c.point_at_x (curr_p); - curr_y = CGAL::to_double(px.y()); - QPointF curr( curr_x, curr_y ); - pts.push_back( curr ); - }// for - }// else - pts.push_back(coord_target ); - } - //created from the outer boundary of the face - } while (++cc != f->outer_ccb()); - - // make polygon from the outer ccb of the face 'f' - QPolygonF pgn( pts ); - - // fill the face according to its color (stored at any of her - // incidents curves) - QBrush oldBrush = painter->brush( ); - QColor def_bg_color = this->backgroundColor; - if (! f->color().isValid()) - { - painter->setBrush( def_bg_color ); - } - else - { - painter->setBrush( f->color( ) ); - } - painter->drawPolygon( pgn ); - painter->setBrush( oldBrush ); - } - else - { - QRectF rect = this->viewportRect( ); - QColor color = this->backgroundColor; - painter->fillRect( rect, color ); - } - } -#endif - - template < typename CircularKernel > - void paintFace(Face_handle f, QPainter* painter, - CGAL::Arr_circular_arc_traits_2 /* traits */) - { - if ( f->is_unbounded( ) ) - { - QRectF rect = this->viewportRect( ); - QColor color = this->backgroundColor; - if ( f->color().isValid() ) - color = f->color(); - painter->fillRect( rect, color ); - return; - } - QPainterPath path; - bool isFirstArc = true; - Ccb_halfedge_circulator cc=f->outer_ccb(); - do - { - if ( this->antenna( cc ) ) - continue; - - if ( isFirstArc ) - { - isFirstArc = false; - X_monotone_curve_2 c = cc->curve( ); - - QPointF source( to_double(c.source().x()), to_double(c.source().y()) ); - QPointF target( to_double(c.target().x()), to_double(c.target().y()) ); - if ( ! this->isProperOrientation( cc ) ) - { - std::swap( source, target ); - } - - QPointF circleCenter( to_double(c.supporting_circle().center().x()), - to_double(c.supporting_circle().center().y()) ); - //this->drawDiagnosticArc( circleCenter, source, target, painter ); - - std::swap( source, target ); - double asource = atan2( -(source - circleCenter).y(), - (source - circleCenter).x() ); - double atarget = atan2( -(target - circleCenter).y(), - (target - circleCenter).x() ); - double aspan = atarget - asource; - std::swap( source, target ); - - path.moveTo( source ); - path.arcTo( convert(c.supporting_circle().bbox()), asource * 180/M_PI, - aspan * 180/M_PI ); - path.lineTo( target ); - } - else - { - X_monotone_curve_2 c = cc->curve( ); - QPointF source( to_double(c.source().x()), to_double(c.source().y()) ); - QPointF target( to_double(c.target().x()), to_double(c.target().y()) ); - if ( ! this->pathTouchingSource( path, c ) ) - std::swap( source, target ); - - QPointF circleCenter( to_double(c.supporting_circle().center().x()), - to_double(c.supporting_circle().center().y()) ); - //this->drawDiagnosticArc( circleCenter, source, target, painter ); - - std::swap( source, target ); - double asource = atan2( -(source - circleCenter).y(), - (source - circleCenter).x() ); - double atarget = atan2( -(target - circleCenter).y(), - (target - circleCenter).x() ); - double aspan = atarget - asource; - std::swap( source, target ); - - path.arcTo( convert(c.supporting_circle().bbox()), asource * 180/M_PI, - aspan * 180/M_PI ); - path.lineTo( target ); - } - } while (++cc != f->outer_ccb()); - - if ( f->color().isValid() ) - { - QPen savePen = painter->pen(); - QBrush saveBrush = painter->brush(); - QPen pen = painter->pen(); - pen.setColor( f->color() ); - - painter->setPen( pen ); - painter->setBrush( f->color() ); - painter->drawPath( path ); - painter->setPen( savePen ); - painter->setBrush( saveBrush ); - } - } - - void drawDiagnosticArc( QPointF c, QPointF s, QPointF t, QPainter* qp ) - { - QBrush saveBrush = qp->brush( ); - double r = QLineF( c, s ).length(); - QRectF bb( c.x() - r, c.y() - r, 2*r, 2*r ); - - QPainterPath path; - // because we flipped the y-axis in our view, we need to flip our angles - // with respect to the y-axis. we can do this by flipping s and t, then - // negating their y-values - std::swap( s, t ); - double as = atan2( -(s - c).y(), (s - c).x() ); - double at = atan2( -(t - c).y(), (t - c).x() ); - double aspan = at - as; - - path.moveTo( c ); - path.lineTo( s ); - path.arcTo( bb, as * 180/M_PI, aspan * 180/M_PI ); - path.closeSubpath( ); - qp->drawEllipse( bb ); - - qp->setBrush( ::Qt::red ); - qp->fillPath( path, qp->brush() ); - qp->setBrush( saveBrush ); - - } - - /** - Return false if the tip of the given curve doesn't align with either of the - endpoints of the next curve. - */ - bool isProperOrientation( Ccb_halfedge_circulator cc ) - { - Ccb_halfedge_circulator ccnext = cc; - Halfedge_handle he = cc; - X_monotone_curve_2 thisCurve = he->curve( ); - ccnext++; - while ( this->antenna( ccnext ) ) ccnext++; - Halfedge_handle next_he = ccnext; - X_monotone_curve_2 nextCurve = next_he->curve( ); - - QPointF thisTarget( to_double(thisCurve.target().x()), - to_double(thisCurve.target().y()) ); - QPointF nextSource( to_double(nextCurve.source().x()), - to_double(nextCurve.source().y()) ); - QPointF nextTarget( to_double(nextCurve.target().x()), - to_double(nextCurve.target().y()) ); - double dist1 = QLineF( thisTarget, nextSource ).length(); - double dist2 = QLineF( thisTarget, nextTarget ).length(); - bool res = ( dist1 < 1e-2 || dist2 < 1e-2 ); - - return res; - } - - bool pathTouchingSource( const QPainterPath& path, X_monotone_curve_2 c ) - { - QPointF a = path.currentPosition( ); - QPointF b( to_double(c.source().x()), to_double(c.source().y()) ); - // QPointF d( to_double(c.target().x()), to_double(c.target().y()) ); - bool res = (QLineF( a, b ).length() < 1e-2); - - return res; - } - -#if 0 - template < typename CircularKernel > - void paintFace(Face_handle f, QPainter* painter, - CGAL::Arr_circular_arc_traits_2 /* traits */) - { - // std::cout << "face begin" << std::endl; - if (! f->is_unbounded()) // f is not the unbounded face - { - QBrush oldBrush = painter->brush( ); - QColor def_bg_color = this->backgroundColor; - if (! f->color().isValid()) - { - painter->setBrush( def_bg_color ); - } - else - { - painter->setBrush( f->color( ) ); - } - - // approach: draw a closed path with arcs - QPainterPath path; - //path.setFillRule( ::Qt::WindingFill ); - - bool isFirstArc = true; - Ccb_halfedge_circulator cc=f->outer_ccb(); - do - { - if (this->antenna(cc)) - continue; - - Halfedge_handle he = cc; - X_monotone_curve_2 c = he->curve(); // circular arc - - const typename CircularKernel::Circle_2& circ = c.supporting_circle(); - const typename CircularKernel::Point_2& center = circ.center(); - QPointF source( to_double(c.source().x()), to_double(c.source().y()) ); - QPointF target( to_double(c.target().x()), to_double(c.target().y()) ); - - if ( isFirstArc ) - { - isFirstArc = false; - // make sure we are going the right way - Ccb_halfedge_circulator ccnext = cc; - ccnext++; - while ( this->antenna( ccnext ) ) ccnext++; - Halfedge_handle next_he = ccnext; - X_monotone_curve_2 next_c = next_he->curve( ); - QPointF next_source( to_double(next_c.source().x()), - to_double(next_c.source().y()) ); - QPointF next_target( to_double(next_c.target().x()), - to_double(next_c.target().y()) ); - // std::cout << "next curve's points: " << std::endl - // << " s: " << next_source.x( ) - // << " " << next_source.y( ) << std::endl - // << " t: " << next_target.x( ) - // << " " << next_target.y( ) << std::endl; - double dist1 = QLineF( target, next_source ).length(); - double dist2 = QLineF( target, next_target ).length(); - if ( dist1 > 1e-2 && dist2 > 1e-2 ) - { - std::cout << "swapping first curve points" << std::endl; - std::swap( source, target ); - } - - path.moveTo( source ); - } - else - { - //bool source_is_left = (source.x() < target.x()); - double dist = QLineF( path.currentPosition(), source ).length( ); - // if ( dist > 1e-2 ) - // { - // std::cout << "swapping source and target " << dist - // << std::endl; - // std::swap( source, target ); - // } - } - // std::cout << "currentPosition: " << path.currentPosition().x() - // << ", " << path.currentPosition().y() << std::endl; - std::stringstream ss; - ss << " source: " << to_double(source.x( )) << ", " - << to_double(source.y()) << std::endl - << " target: " << to_double(target.x( )) << ", " - << to_double(target.y()) << std::endl; - -#if 0 - source = QPointF( to_double(c.source().x()), to_double(c.source().y())); - target = QPointF( to_double(c.target().x()), to_double(c.target().y())); - double asource = std::atan2( -to_double(source.y() - center.y()), - to_double(source.x() - center.x())); - double atarget = std::atan2( -to_double(target.y() - center.y()), - to_double(target.x() - center.x())); -#endif - double asource = std::atan2( to_double(source.y() - center.y()), - to_double(source.x() - center.x()) ); - double atarget = std::atan2( to_double(target.y() - center.y()), - to_double(target.x() - center.x()) ); - - ss << " asource: " << (asource * 180/M_PI) << std::endl - << " atarget: " << (atarget * 180/M_PI) << std::endl; - - //std::swap(asource, atarget); - double aspan = atarget - asource; - ss << " aspan: " << (aspan * 180/M_PI) << std::endl; - - if(aspan < 0.) - aspan += 2 * CGAL_PI; - - const double coeff = 180*16/CGAL_PI; - double circR = sqrt(to_double(circ.squared_radius())); - -#if 0 - painter->drawEllipse( to_double( center.x() - circR ), - to_double( center.y() - circR ), - 2*circR, 2*circR ); -#endif - QPointF curPos = path.currentPosition( ); - //path.lineTo( to_double(target.x( )), to_double(target.y()) ); - -#if 0 - ss << "drawing line from " << curPos.x( ) << ", " << curPos.y( ) - << " to " - << to_double(target.x( )) << ", " << to_double(target.y()); -#endif - // std::cout << ss.str( ) << std::endl; - path.arcTo( convert(circ.bbox()), asource * 180/CGAL_PI, - aspan *180/CGAL_PI ); -#if 0 - qp->drawArc(convert(circ.bbox()), - (int)(asource * coeff), - (int)(aspan * coeff)); -#endif - } while (++cc != f->outer_ccb()); - - // fill the face according to its color (stored at any of her - // incidents curves) -#if 0 - painter->drawPolygon( pgn ); -#endif - path.closeSubpath( ); -#if 0 - QPainterPathStroker stroker; - QPainterPath fillablePath = stroker.createStroke( path ); -#endif - painter->fillPath( path, painter->brush() ); -#if 0 - QPolygonF fillIt = path.toFillPolygon( ); - painter->drawPolygon( fillIt ); -#endif - //painter->drawPath( path ); - //painter->fillPath( path, painter->brush() ); - painter->setBrush( oldBrush ); - } - else - { - QRectF rect = this->viewportRect( ); - QColor color = this->backgroundColor; - painter->fillRect( rect, color ); - } - } -#endif - - //void cacheCurveBoundingRects( ); - - void updateBoundingBox(); - - template < typename TTraits> - void updateBoundingBox(TTraits traits ); - - template < typename Kernel_> - void updateBoundingBox(CGAL::Arr_linear_traits_2 traits); - - // template < typename Coefficient_> - // void updateBoundingBox(CGAL::Arr_algebraic_segment_traits_2 - // traits); - - Arrangement* arr; - ArrangementPainterOstream< Traits > painterostream; - CGAL::Qt::Converter< Kernel > convert; - std::map< Curve_iterator, CGAL::Bbox_2 > curveBboxMap; -}; // class ArrangementGraphicsItem - - template < typename Arr_, class ArrTraits > - ArrangementGraphicsItem< Arr_, ArrTraits >:: - ArrangementGraphicsItem( Arrangement* arr_ ): - arr( arr_ ), - painterostream( 0 ) - { - if ( this->arr->number_of_vertices( ) == 0 ) { - this->hide( ); - } - this->updateBoundingBox( ); - this->setZValue( 3 ); - } - - template < typename Arr_, typename ArrTraits > - QRectF - ArrangementGraphicsItem< Arr_, ArrTraits >:: - boundingRect( ) const - { - QRectF rect = this->convert( this->bb ); - return rect; - } - - template < typename Arr_, typename ArrTraits > - void - ArrangementGraphicsItem< Arr_, ArrTraits >:: - paint(QPainter* painter, - const QStyleOptionGraphicsItem* /* option */, - QWidget* /*widget*/) - { - this->paint( painter, ArrTraits( ) ); - } - - template < typename Arr_, typename ArrTraits > - template < typename TTraits > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - paint(QPainter* painter, TTraits /* traits */) - { - this->paintFaces( painter ); - - painter->setPen( this->verticesPen ); - this->painterostream = - ArrangementPainterOstream< Traits >( painter, this->boundingRect( ) ); - this->painterostream.setScene( this->scene ); - - for ( Vertex_iterator it = this->arr->vertices_begin( ); - it != this->arr->vertices_end( ); ++it ) - { - Point_2 p = it->point( ); - Kernel_point_2 pt( p.x( ), p.y( ) ); - this->painterostream << pt; - } - painter->setPen( this->edgesPen ); - for ( Edge_iterator it = this->arr->edges_begin( ); - it != this->arr->edges_end( ); ++it ) - { - X_monotone_curve_2 curve = it->curve( ); - this->painterostream << curve; - } - } - - template < typename Arr_, typename ArrTraits > - template < typename Kernel_ > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - paint(QPainter* painter, CGAL::Arr_linear_traits_2< Kernel_ > /* traits */) - { - this->updateBoundingBox( ); - this->paintFaces( painter ); - painter->setPen( this->verticesPen ); - - this->painterostream = - ArrangementPainterOstream< Traits >( painter, this->boundingRect( ) ); - this->painterostream.setScene( this->scene ); - - for ( Vertex_iterator it = this->arr->vertices_begin( ); - it != this->arr->vertices_end( ); ++it ) - { - Point_2 pt = it->point( ); - this->painterostream << pt; - } - painter->setPen( this->edgesPen ); - for ( Edge_iterator it = this->arr->edges_begin( ); - it != this->arr->edges_end( ); ++it ) - { - X_monotone_curve_2 curve = it->curve( ); - this->painterostream << curve; - } - } - - template < typename Arr_, typename ArrTraits > - template < typename CircularKernel > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - paint(QPainter* painter, - CGAL::Arr_circular_arc_traits_2< CircularKernel > /* traits */) - { - typedef Kernel_point_2 Non_arc_point_2; - typedef typename Traits::Point_2 Arc_point_2; - - this->paintFaces( painter ); - - painter->setPen( this->verticesPen ); - this->painterostream = - ArrangementPainterOstream< Traits >( painter, this->boundingRect( ) ); - this->painterostream.setScene( this->scene ); - - for ( Vertex_iterator it = this->arr->vertices_begin( ); - it != this->arr->vertices_end( ); ++it ) - { - Arc_point_2 pt = it->point( ); - Non_arc_point_2 pt2(CGAL::to_double(pt.x( )), CGAL::to_double(pt.y()) ); - this->painterostream << pt2; - } - painter->setPen( this->edgesPen ); - for ( Edge_iterator it = this->arr->edges_begin( ); - it != this->arr->edges_end( ); ++it ) - { - X_monotone_curve_2 curve = it->curve( ); - this->painterostream << curve; - } - } - -#if 0 - template < typename Arr_, typename ArrTraits > - template < typename Coefficient_ > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - paint(QPainter* painter, - CGAL::Arr_algebraic_segment_traits_2< Coefficient_ > /* traits */) - { - painter->setPen( this->verticesPen ); - QRectF clipRect = this->boundingRect( ); - if ( std::isinf(clipRect.left( )) || - std::isinf(clipRect.right( )) || - std::isinf(clipRect.top( )) || - std::isinf(clipRect.bottom( )) ) - { - clipRect = this->viewportRect( ); - } - - this->painterostream = - ArrangementPainterOstream< Traits >( painter, clipRect ); - this->painterostream.setScene( this->scene ); - - for ( Vertex_iterator it = this->arr->vertices_begin( ); - it != this->arr->vertices_end( ); ++it ) - { - Point_2 p = it->point( ); - //std::pair< double, double > approx = p.to_double( ); - //Kernel_point_2 pt( approx.first, approx.second ); - //this->painterostream << pt; - this->painterostream << p; - } - painter->setPen( this->edgesPen ); - for ( Edge_iterator it = this->arr->edges_begin( ); - it != this->arr->edges_end( ); ++it ) - { - X_monotone_curve_2 curve = it->curve( ); - this->painterostream << curve; - } - } -#endif - - // We let the bounding box only grow, so that when vertices get removed - // the maximal bbox gets refreshed in the GraphicsView - template < typename Arr_, typename ArrTraits > - void ArrangementGraphicsItem< Arr_, ArrTraits >::updateBoundingBox( ) - { - this->updateBoundingBox( ArrTraits( ) ); - } - - template < typename Arr_, typename ArrTraits > - template < typename TTraits > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - updateBoundingBox(TTraits /* traits */) - { - this->prepareGeometryChange( ); - if ( this->arr->number_of_vertices( ) == 0 ) - { - this->bb = Bbox_2( 0, 0, 0, 0 ); - this->bb_initialized = false; - return; - } - else - { - this->bb = this->arr->vertices_begin( )->point( ).bbox( ); - this->bb_initialized = true; - } - - for ( Curve_iterator it = this->arr->curves_begin( ); - it != this->arr->curves_end( ); - ++it ) - { - if ( this->curveBboxMap.count( it ) == 0 ) - { - this->curveBboxMap[ it ] = it->bbox( ); - } - this->bb = this->bb + this->curveBboxMap[ it ]; - } - } - - template < typename Arr_, typename ArrTraits > - template < typename Kernel_ > - void - ArrangementGraphicsItem< Arr_, ArrTraits >:: - updateBoundingBox(CGAL::Arr_linear_traits_2< Kernel_ > /* traits */) - { - this->prepareGeometryChange( ); - QRectF clipRect = this->viewportRect( ); - this->convert = Converter( clipRect ); - - if ( ! clipRect.isValid( ) /*|| this->arr->number_of_vertices( ) == 0*/ ) - { - this->bb = Bbox_2( 0, 0, 0, 0 ); - this->bb_initialized = false; - return; - } - else - { - this->bb = this->convert( clipRect ).bbox( ); - this->bb_initialized = true; - } - - for ( Curve_iterator it = this->arr->curves_begin( ); - it != this->arr->curves_end( ); - ++it ) - { - if ( it->is_segment( ) ) - { - this->bb = this->bb + it->segment( ).bbox( ); - } - else if ( it->is_ray( ) ) - { - QLineF qclippedRay = this->convert( it->ray( ) ); - Segment_2 clippedRay = this->convert( qclippedRay ); - this->bb = this->bb + clippedRay.bbox( ); - } - else // ( it->is_line( ) ) - { - QLineF qclippedLine = this->convert( it->line( ) ); - Segment_2 clippedLine = this->convert( qclippedLine ); - this->bb = this->bb + clippedLine.bbox( ); - } - } - } - -#if 0 - template < typename Arr_, typename ArrTraits > - template < typename Coefficient_ > - void ArrangementGraphicsItem< Arr_, ArrTraits >:: - updateBoundingBox(CGAL::Arr_algebraic_segment_traits_2 traits) - { - this->prepareGeometryChange( ); - if ( this->arr->number_of_vertices( ) == 0 ) - { - this->bb = Bbox_2( 0, 0, 0, 0 ); - this->bb_initialized = false; - return; - } - else - { - //std::pair< double, double > approx = - // this->arr->vertices_begin( )->point( ).to_double( ); - //this->bb = CGAL::Bbox_2( approx.first, approx.second, - // approx.first, approx.second ); - this->bb = CGAL::Bbox_2( 0, 0, 0, 0 ); - this->bb_initialized = true; - } - typename Traits::Make_x_monotone_2 make_x_monotone_2 = - traits.make_x_monotone_2_object( ); - for ( Curve_iterator it = this->arr->curves_begin( ); - it != this->arr->curves_end( ); - ++it ) - { - std::vector< CGAL::Object > cvs; - make_x_monotone_2( *it, std::back_inserter( cvs ) ); - for ( unsigned int i = 0 ; i < cvs.size( ); ++i ) - { - X_monotone_curve_2 cv; - CGAL::assign( cv, cvs[ i ] ); - this->bb = this->bb + cv.bbox( ); - } - } - } -#endif - - template < typename Arr_, typename ArrTraits > - void ArrangementGraphicsItem< Arr_, ArrTraits >::modelChanged( ) - { - if ( this->arr->is_empty( ) ) - { - this->hide( ); - } - else - { - this->show( ); - } - this->updateBoundingBox( ); - this->update( ); - } - - /** - Specialized methods: - updateBoundingBox - */ -#if 0 - template < typename Arr_, typename Kernel_ > - class ArrangementGraphicsItem< Arr_, CGAL::Arr_linear_traits_2< Kernel_ > > : - public ArrangementGraphicsItemBase - { - typedef Arr_ Arrangement; - typedef ArrangementGraphicsItemBase Superclass; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Arrangement::Curve_iterator Curve_iterator; - typedef typename Arrangement::Edge_iterator Edge_iterator; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - - public: - ArrangementGraphicsItem( Arrangement* arr_ ): - arr( arr_ ), - painterostream( 0 ) - { - if ( this->arr->number_of_vertices( ) == 0 ) { - this->hide( ); - } - this->updateBoundingBox( ); - this->setZValue( 3 ); - } - - public: // methods -#if 0 - void modelChanged( ) - { - if ( this->arr->is_empty( ) ) - { - this->hide( ); - } - else - { - this->show( ); - } - this->updateBoundingBox( ); - this->update( ); - } - - // @override QGraphicsItem::boundingRect - QRectF boundingRect( ) const - { - QRectF rect = this->convert( this->bb ); - return rect; - } -#endif - - // @override QGraphicsItem::paint -#if 0 - virtual void paint( QPainter* painter, - const QStyleOptionGraphicsItem* option, - QWidget* widget ) - { - this->updateBoundingBox( ); - painter->setPen( this->verticesPen ); - this->painterostream = - ArrangementPainterOstream< Traits >( painter, this->boundingRect( ) ); - this->painterostream.setScene( this->scene ); - - for ( Vertex_iterator it = this->arr->vertices_begin( ); - it != this->arr->vertices_end( ); ++it ) - { - Point_2 pt = it->point( ); - this->painterostream << pt; - } - painter->setPen( this->edgesPen ); - for ( Edge_iterator it = this->arr->edges_begin( ); - it != this->arr->edges_end( ); ++it ) - { - X_monotone_curve_2 curve = it->curve( ); - this->painterostream << curve; - } - } -#endif - - protected: // methods -#if 0 - void updateBoundingBox( ) - { - this->prepareGeometryChange( ); - QRectF clipRect = this->viewportRect( ); - this->convert = Converter( clipRect ); - - if ( ! clipRect.isValid( ) /*|| this->arr->number_of_vertices( ) == 0*/ ) - { - this->bb = Bbox_2( 0, 0, 0, 0 ); - this->bb_initialized = false; - return; - } - else - { - this->bb = this->convert( clipRect ).bbox( ); - this->bb_initialized = true; - } - - for ( Curve_iterator it = this->arr->curves_begin( ); - it != this->arr->curves_end( ); - ++it ) - { - if ( it->is_segment( ) ) - { - this->bb = this->bb + it->segment( ).bbox( ); - } - else if ( it->is_ray( ) ) - { - QLineF qclippedRay = this->convert( it->ray( ) ); - Segment_2 clippedRay = this->convert( qclippedRay ); - this->bb = this->bb + clippedRay.bbox( ); - } - else // ( it->is_line( ) ) - { - QLineF qclippedLine = this->convert( it->line( ) ); - Segment_2 clippedLine = this->convert( qclippedLine ); - this->bb = this->bb + clippedLine.bbox( ); - } - } - } -#endif - - protected: // fields - Arrangement* arr; - ArrangementPainterOstream< Traits > painterostream; - CGAL::Qt::Converter< Kernel > convert; - }; // class ArrangementGraphicsItem -#endif - } // namespace Qt } // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItemTyped.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItemTyped.h new file mode 100644 index 00000000000..c1778335399 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementGraphicsItemTyped.h @@ -0,0 +1,142 @@ +// Copyright (c) 2008, 2012, 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#ifndef CGAL_QT_ARRANGEMENT_GRAPHICS_ITEM_TYPED_H +#define CGAL_QT_ARRANGEMENT_GRAPHICS_ITEM_TYPED_H + +#include +#include +#include +#include +#include + +#include "ArrangementGraphicsItem.h" +#include "FloodFill.h" +#include "ForwardDeclarations.h" +#include "PointsGraphicsItem.h" + +namespace CGAL +{ +namespace Qt +{ + +template +class ArrangementGraphicsItem : public ArrangementGraphicsItemBase +{ + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Arrangement::Halfedge Halfedge; + typedef typename Arrangement::Halfedge_handle Halfedge_handle; + typedef typename Arrangement::Face_handle Face_handle; + typedef typename Arrangement::Hole_iterator Hole_iterator; + typedef typename Arrangement::Ccb_halfedge_circulator Ccb_halfedge_circulator; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Point_2 Point_2; + +public: + /*! Constructor */ + ArrangementGraphicsItem(Arrangement* t_); + +public: + void modelChanged() override; + QRectF boundingRect() const override; + QRectF getInterestingViewport() const override; + void paint( + QPainter* painter, const QStyleOptionGraphicsItem* option, + QWidget* widget) override; + +protected: + void updatePointsItem(); + + template + void paint(QPainter*, const TTraits&); + + template + void + paint(QPainter*, const CGAL::Arr_algebraic_segment_traits_2&); + + template + void paint( + QPainter*, + const CGAL::Arr_rational_function_traits_2&); + + template + void paintWithFloodFill(QPainter*, const TTraits&); + + void updateBoundingBox(); + + template + void paintEdges(QPainter*, const TTraits&); + + template + void paintEdges( + QPainter*, const CGAL::Arr_algebraic_segment_traits_2&); + + void paintFaces(QPainter* painter); + + void paintFacesFloodFill(QPainter*, QImage&); + + void paintFace(Face_handle f, QPainter* painter); + + void visit_ccb_faces(Face_handle& fh, QPainter* painter); + + /*! antenna - return true if the halfedge and its + * twin point to the same face. + */ + bool antenna(Halfedge_handle h); + + template + void paintFace(Face_handle, QPainter*, ArrTraits); + + template + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_segment_traits_2&); + + template + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_polyline_traits_2&); + + template + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_conic_traits_2&); + + template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits>&); + + template + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_algebraic_segment_traits_2&); + + template + void paintFace( + Face_handle f, QPainter* painter, + const CGAL::Arr_linear_traits_2&); + +protected: + Arrangement* arr; + PointsGraphicsItem* pointsGraphicsItem; + CGAL::Bbox_2 bb; + FloodFill flood_fill; + QImage tempImage; +}; // class ArrangementGraphicsItem + +} // namespace Qt +} // namespace CGAL + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp new file mode 100644 index 00000000000..8e1f6bbc972 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.cpp @@ -0,0 +1,169 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "ArrangementIO.h" +#include "ArrangementDemoTab.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "Conic_reader.h" + +#include +#include +#include + +template < + typename Arrangement, + typename Traits = typename Arrangement::Geometry_traits_2> +struct ArrReader +{ + Arrangement* operator()(std::ifstream& ifs) + { + using Text_formatter = CGAL::Arr_text_formatter; + using ArrFormatter = CGAL::Arr_with_history_text_formatter; + + ArrFormatter arrFormatter; + auto arr = new Arrangement(); + CGAL::read(*arr, ifs, arrFormatter); + return arr; + } +}; + +#ifdef CGAL_USE_CORE +template < + typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, + typename Nt_traits_> +struct ArrReader< + Arrangement, CGAL::Arr_conic_traits_2> +{ + using Traits = typename Arrangement::Geometry_traits_2; + using Curve_2 = typename Arrangement::Curve_2; + + Arrangement* operator()(std::ifstream& ifs) + { + Conic_reader conicReader; + std::vector curve_list; + CGAL::Bbox_2 bbox; + conicReader.read_data(ifs, std::back_inserter(curve_list), bbox); + auto arr = new Arrangement(); + CGAL::insert(*arr, curve_list.begin(), curve_list.end()); + return arr; + } +}; + +template < + typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, + typename Nt_traits_, typename Bounding_traits_> +struct ArrReader< + Arrangement, CGAL::Arr_Bezier_curve_traits_2< + Rat_kernel_, Alg_kernel_, Nt_traits_, Bounding_traits_>> +{ + Arrangement* operator()(std::ifstream&) { return nullptr; } +}; + +template +struct ArrReader< + Arrangement, CGAL::Arr_rational_function_traits_2> +{ + Arrangement* operator()(std::ifstream&) { return nullptr; } +}; +#endif + +std::pair +ArrangementIO::read(std::ifstream& ifs) +{ + // read type info + while (ifs.peek() == '#' || std::isspace(ifs.peek())) ifs.get(); + + int tt_int; + ifs >> tt_int; + auto tt = static_cast(tt_int); + + std::pair res; + demo_types::visitArrangementType(tt, [&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + auto arr = ArrReader{}(ifs); + res = {CGAL::make_object(arr), demo_types::enumFromArrType()}; + }); + return res; +} + +template < + typename Arrangement, + typename Traits = typename Arrangement::Geometry_traits_2> +struct ArrWriter +{ + void operator()(Arrangement* arr, std::ofstream& ofs) + { + using TextFormatter = CGAL::Arr_text_formatter; + using ArrFormatter = CGAL::Arr_with_history_text_formatter; + + ArrFormatter arrFormatter; + CGAL::write(*arr, ofs, arrFormatter); + } +}; + +#ifdef CGAL_USE_CORE +template < + typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, + typename Nt_traits_> +struct ArrWriter< + Arrangement, CGAL::Arr_conic_traits_2> +{ + using Traits = typename Arrangement::Geometry_traits_2; + using Curve_2 = typename Arrangement::Curve_2; + + void operator()(Arrangement* arr, std::ofstream& ofs) + { + Conic_reader conicReader; + conicReader.write_data(ofs, arr->curves_begin(), arr->curves_end()); + } +}; + +template < + typename Arrangement, typename Rat_kernel_, typename Alg_kernel_, + typename Nt_traits_, typename Bounding_traits_> +struct ArrWriter< + Arrangement, CGAL::Arr_Bezier_curve_traits_2< + Rat_kernel_, Alg_kernel_, Nt_traits_, Bounding_traits_>> +{ + void operator()(Arrangement*, std::ofstream&) { } +}; + +template +struct ArrWriter< + Arrangement, CGAL::Arr_rational_function_traits_2> +{ + void operator()(Arrangement*, std::ofstream&) { } +}; +#endif + +bool ArrangementIO::write( + const std::pair& arr_pair, + std::ofstream& ofs) +{ + auto tt = arr_pair.second; + auto arr_obj = arr_pair.first; + + // write type info + ofs << "# " << static_cast(tt) << std::endl; + + bool result = false; + demo_types::visitArrangementType(tt, [&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + Arrangement* arr; + if (CGAL::assign(arr, arr_obj)) + { + ArrWriter{}(arr, ofs); + result = true; + } + }); + return result; +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.h new file mode 100644 index 00000000000..b62ca3b5f52 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementIO.h @@ -0,0 +1,35 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_IO_H +#define ARRANGEMENT_DEMO_IO_H + +#include +#include + +namespace demo_types +{ +enum class TraitsType : int; +} + +namespace CGAL +{ +class Object; +} + +struct ArrangementIO +{ + std::pair read(std::ifstream&); + bool + write(const std::pair&, std::ofstream&); +}; + +#endif // ARRANGEMENT_DEMO_IO_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp new file mode 100644 index 00000000000..1fa59ad88de --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.cpp @@ -0,0 +1,670 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Saurabh Singh +// Ahmed Essam + +#include "ArrangementPainterOstream.h" +#include "ArrangementTypes.h" +#include + +#include + +namespace CGAL +{ +namespace Qt +{ + +// Instantiation of Arr_segment_traits_2 +template +ArrangementPainterOstream>& +ArrangementPainterOstream>::operator<<( + const X_monotone_curve_2& curve) +{ + const Point_2& p1 = curve.source(); + const Point_2& p2 = curve.target(); + Segment_2 seg(p1, p2); + + // skip segments outside our view + QRectF seg_bb = this->convert(seg.bbox()); + if ( + this->clippingRect.isValid() && !this->clippingRect.intersects(seg_bb) && + (!seg.is_horizontal() && !seg.is_vertical())) + { return *this; } + + this->painterOstream << seg; + return *this; +} + +// Instantiation of Arr_polyline_traits_2 + +template +ArrangementPainterOstream>& +ArrangementPainterOstream>:: +operator<<(const X_monotone_curve_2& curve) +{ + int cnt = 0; + for (typename X_monotone_curve_2::Subcurve_const_iterator it = + curve.subcurves_begin(); + it != curve.subcurves_end(); ++it) + { + cnt++; + this->painterOstream << *it; + } + + return *this; +} + +// Instantiation of Arr_conic_traits_2 +template +auto ArrangementPainterOstream>::visibleParts(X_monotone_curve_2 curve) + -> std::vector +{ + // see if we intersect the bottom edge of the viewport + Point_2 bottomLeft = this->convert(this->clippingRect.bottomLeft()); + Point_2 bottomRight = this->convert(this->clippingRect.bottomRight()); + Point_2 topLeft = this->convert(this->clippingRect.topLeft()); + Point_2 topRight = this->convert(this->clippingRect.topRight()); + X_monotone_curve_2 bottom = + this->construct_x_monotone_curve_2(bottomLeft, bottomRight); + X_monotone_curve_2 left = + this->construct_x_monotone_curve_2(bottomLeft, topLeft); + X_monotone_curve_2 top = + this->construct_x_monotone_curve_2(topLeft, topRight); + X_monotone_curve_2 right = + this->construct_x_monotone_curve_2(topRight, bottomRight); + + std::vector bottomIntersections; + std::vector leftIntersections; + std::vector topIntersections; + std::vector rightIntersections; + std::vector intersections; + + this->intersect_2(bottom, curve, bottomIntersections); + this->intersect_2(left, curve, leftIntersections); + this->intersect_2(top, curve, topIntersections); + this->intersect_2(right, curve, rightIntersections); + + this->intersect_2(bottom, curve, intersections); + this->intersect_2(left, curve, intersections); + this->intersect_2(top, curve, intersections); + this->intersect_2(right, curve, intersections); + + this->filterIntersectionPoints(intersections); + + Point_2 leftEndpt = curve.source(); + Point_2 rightEndpt = curve.target(); + + if (leftEndpt.x() > rightEndpt.x()) { std::swap(leftEndpt, rightEndpt); } + + QPointF qendpt1 = this->convert(leftEndpt); + QPointF qendpt2 = this->convert(rightEndpt); + + std::list pointList; + for (unsigned int i = 0; i < intersections.size(); ++i) + { + CGAL::Object o = intersections[i]; + std::pair pair; + if (CGAL::assign(pair, o)) + { + Point_2 pt = pair.first; + pointList.push_back(pt); + } + } + + bool includeLeftEndpoint = this->clippingRect.contains(qendpt1); + bool includeRightEndpoint = this->clippingRect.contains(qendpt2); + if (includeLeftEndpoint) { pointList.push_front(leftEndpt); } + + if (includeRightEndpoint) { pointList.push_back(rightEndpt); } + + // TODO: make ArrangementPainterOstream take traits object + Traits traits; + Construct_x_monotone_subcurve_2 construct_x_monotone_subcurve_2{ + &traits}; + std::vector clippings; + typename std::list::iterator pointListItr = pointList.begin(); + for (unsigned int i = 0; i < pointList.size(); i += 2) + { + typename Traits::Point_2 p1 = *pointListItr++; + typename Traits::Point_2 p2 = *pointListItr++; + X_monotone_curve_2 subcurve = + construct_x_monotone_subcurve_2(curve, p1, p2); + clippings.push_back(subcurve); + } + + return clippings; +} + +template +void ArrangementPainterOstream< + CGAL::Arr_conic_traits_2>:: + filterIntersectionPoints(std::vector& res) +{ + std::vector> tmp; + + // filter out the non-intersection point results + for (unsigned int i = 0; i < res.size(); ++i) + { + CGAL::Object obj = res[i]; + std::pair pair; + if (CGAL::assign(pair, obj)) { tmp.push_back(pair); } + } + res.clear(); + + // sort the intersection points by x-coord + Compare_intersection_point_result compare_intersection_point_result; + std::sort(tmp.begin(), tmp.end(), compare_intersection_point_result); + + // box up the sorted elements + for (unsigned int i = 0; i < tmp.size(); ++i) + { + std::pair pair = tmp[i]; + CGAL::Object o = CGAL::make_object(pair); + res.push_back(o); + } +} + +template +ArrangementPainterOstream< + CGAL::Arr_conic_traits_2>& +ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) +{ + CGAL::Bbox_2 bb = curve.bbox(); + QRectF qbb = this->convert(bb); + + // quick cull + if (this->clippingRect.isValid() && !this->clippingRect.intersects(qbb)) + { return *this; } + + // get number of segments + QGraphicsView* view = this->scene->views().first(); + int xmin = view->mapFromScene(bb.xmin(), bb.ymin()).x(); + int xmax = view->mapFromScene(bb.xmax(), bb.ymin()).x(); + // can be negitive due to rotation trasnformation + size_t n = static_cast(std::abs(xmax - xmin)); + if (n == 0) { return *this; } + + auto paintCurve = [&](auto&& curve_) { + std::vector> app_pts; + app_pts.reserve(n + 1); + curve_.polyline_approximation(n, std::back_inserter(app_pts)); + + auto p_curr = app_pts.begin(); + auto end_pts = app_pts.end(); + auto p_next = p_curr + 1; + int count = 0; + do + { + QPointF p1(p_curr->first, p_curr->second); + QPointF p2(p_next->first, p_next->second); + this->qp->drawLine(p1, p2); + p_curr++; + p_next++; + ++count; + } while (p_next != end_pts); + }; + + if (this->clippingRect.isValid()) + { + std::vector visibleParts; + if (this->clippingRect.contains(qbb)) + visibleParts.push_back(curve); + else + visibleParts = this->visibleParts(curve); + + for (auto& visiblePart : visibleParts) paintCurve(visiblePart); + } + else + { // draw the whole curve + paintCurve(curve); + } + + return *this; +} + +// Instantiation of Arr_Bezier_traits_2 +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +std::vector> +ArrangementPainterOstream>::getPoints(const X_monotone_curve_2& curve) +{ + std::pair param_range = curve.parameter_range(); + auto&& supporting_curve = curve.supporting_curve(); + + std::vector> sampled_points; + // TODO: get adaptive number of samples + unsigned int number_of_samples = + 100 * (param_range.second - param_range.first); + sampled_points.reserve(number_of_samples); + + supporting_curve.sample( + param_range.first, param_range.second, number_of_samples, + std::back_inserter(sampled_points)); + return sampled_points; +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) + -> ArrangementPainterOstream& +{ + auto sampled_points = this->getPoints(curve); + if (sampled_points.empty()) return *this; + + QPainterPath painterPath; + painterPath.moveTo(sampled_points[0].first, sampled_points[0].second); + + for (auto& p : sampled_points) painterPath.lineTo(p.first, p.second); + + this->qp->drawPath(painterPath); + return *this; +} + +// Instantiation of Arr_linear_traits_2 + +template +ArrangementPainterOstream>& +ArrangementPainterOstream>::operator<<( + const X_monotone_curve_2& curve) +{ + if (curve.is_segment()) + { + Segment_2 seg = curve.segment(); + + // skip segments outside our view + QRectF seg_bb = this->convert(seg.bbox()); + if ( + this->clippingRect.isValid() && + !this->clippingRect.intersects(seg_bb) & + (!seg.is_horizontal() && !seg.is_vertical())) + { return *this; } + + this->painterOstream << seg; + } + else if (curve.is_ray()) + { + Ray_2 ray = curve.ray(); + QLineF qseg = this->convert(ray); + if (qseg.isNull()) + { // it's out of view + return *this; + } + Segment_2 seg = this->convert(qseg); + this->painterOstream << seg; + } + else // curve.is_line( ) + { + Line_2 line = curve.line(); + QLineF qseg = this->convert(line); + if (qseg.isNull()) + { // it's out of view + return *this; + } + Segment_2 seg = this->convert(qseg); + this->painterOstream << seg; + } + return *this; +} + +// Instantiation of Arr_algebraic_segment_traits_2 +template +static bool lies_on_border( + const ArrangementPainterOstream* apo, const QPointF& point) +{ + QGraphicsView* view = apo->getScene()->views().first(); + qreal width = view->width(); + qreal height = view->height(); + const float tol = 2; + return std::abs(point.x() - width) < tol || point.x() < tol || + std::abs(point.y() - height) < tol || point.y() < tol; +} + +template +void ArrangementPainterOstream< + CGAL::Arr_algebraic_segment_traits_2>::remapFacadePainter() +{ + this->qp->setTransform(this->getPointsListMapping()); +} + +template +QTransform ArrangementPainterOstream< + CGAL::Arr_algebraic_segment_traits_2>::getPointsListMapping() +{ + auto worldTransform = this->qp->transform(); + return this->getPointsListMapping(worldTransform); +} + +template +QTransform +ArrangementPainterOstream>:: + getPointsListMapping(const QTransform& worldTransform) +{ + auto view = this->getView(); + QRectF viewport = this->viewportRect(); + + // (0, 0) ==> map(topLeft) + QPointF dxdy = worldTransform.map(viewport.topLeft()); + // (view.width(), 0) ==> map(bottomRight) + QPointF p1 = worldTransform.map(viewport.topRight()); + // (0, view.height()) ==> map(0, 0) + QPointF p2 = worldTransform.map(viewport.bottomLeft()); + + // x' = m11*x + m21*y + dx + // y' = m22*y + m12*x + dy + float dx = dxdy.x(); + float dy = dxdy.y(); + float m11 = (p1.x() - dx) / view->width(); + float m21 = (p2.x() - dx) / view->height(); + float m22 = (p2.y() - dy) / view->height(); + float m12 = (p1.y() - dy) / view->width(); + + return QTransform{m11, m12, m21, m22, dx, dy}; +} + +template +auto ArrangementPainterOstream>::getPointsList(const X_monotone_curve_2& curve) + -> std::vector +{ + typedef Curve_renderer_facade Facade; + typedef std::pair Coord_2; + typedef std::vector Coord_vec_2; + + std::vector points; + Facade::instance().draw(curve, points); + return points; +} + +template +ArrangementPainterOstream>& +ArrangementPainterOstream>:: +operator<<(const X_monotone_curve_2& curve) +{ + this->qp->save(); + this->remapFacadePainter(); + this->paintCurve(curve); + this->qp->restore(); + return *this; +} + +template +void ArrangementPainterOstream>::paintCurve(const X_monotone_curve_2& curve) +{ + std::vector points = this->getPointsList(curve); + for (auto& vec : points) + { + auto vit = vec.begin(); + QPainterPath path; + QPointF qpt(vit->first, vit->second); + path.moveTo(qpt); + + for (auto& vit : vec) + { + QPointF qpt_new = QPointF(vit.first, vit.second); + if (lies_on_border(this, qpt) && lies_on_border(this, qpt_new)) + path.moveTo(qpt_new); + else + path.lineTo(qpt_new); + qpt = qpt_new; + } + this->qp->drawPath(path); + } +} + +template +void ArrangementPainterOstream< + CGAL::Arr_algebraic_segment_traits_2>::setupFacade() +{ + typedef Curve_renderer_facade Facade; + QGraphicsView* view = this->getView(); + QRectF viewport = this->viewportRect(); + CGAL::Bbox_2 bbox = this->convert(viewport).bbox(); + Facade::setup(bbox, view->width(), view->height()); +} + +// Instantiation of Arr_rational_function_traits_2 + +template +constexpr const T& clamp(const T& v, const T& lo, const T& hi) +{ + return (v < lo) ? lo : (hi < v) ? hi : v; +} + +template +auto ArrangementPainterOstream>::operator<<(const X_monotone_curve_2& curve) -> Self& +{ + QPainterPath painterPath; + const QRectF viewport = this->viewportRect(); + // overshoot so that the slope would be more accurate + double min_y = viewport.top(); + double max_y = viewport.bottom(); + + bool disconnected = true; + bool first_point = true; + + double last_x = 0, last_y = 0; + + // TODO: this is ugly! clean up these conditions + auto path_filler = [&](double x, double y) { + if (y > max_y || y < min_y) + { + double x_ = x; + double y_ = clamp(y, min_y, max_y); + + // make line to the first out of range point + if (!disconnected) { painterPath.lineTo(x_, y_); } + // connect between two out of range points when they cross different + // boundaries + else if ( + (last_y == min_y && y_ == max_y) || (last_y == max_y && y_ == min_y)) + { + painterPath.moveTo(last_x, last_y); + painterPath.lineTo(x_, y_); + } + last_x = x_; + last_y = y_; + + disconnected = true; + } + else if (first_point) + { + painterPath.moveTo(x, y); + disconnected = false; + } + else + { + if (disconnected) + { + painterPath.moveTo(last_x, last_y); + disconnected = false; + } + painterPath.lineTo(x, y); + } + first_point = false; + }; + + this->sample_points(curve, path_filler); + this->qp->drawPath(painterPath); + + return *this; +} + +template +auto ArrangementPainterOstream>::getPointsList(const X_monotone_curve_2& curve) + -> std::vector +{ + std::vector points_list; + Coord_vec_2* cur_list = nullptr; + + const QRectF viewport = this->viewportRect(); + // overshoot so that the slope would be more accurate + double min_y = viewport.top(); + double max_y = viewport.bottom(); + + bool disconnected = true; + + double last_x = 0, last_y = 0; + bool first_point = false; + + // TODO: this is ugly! clean up these conditions + auto path_filler = [&](double x, double y) { + if (y > max_y || y < min_y) + { + double x_ = x; + double y_ = clamp(y, min_y, max_y); + + if (!disconnected) + cur_list->push_back({x_, y_}); + else if ( + (last_y == min_y && y_ == max_y) || (last_y == max_y && y_ == min_y)) + { + cur_list->push_back({last_x, last_y}); + cur_list->push_back({x_, y_}); + } + last_x = x_; + last_y = y_; + + disconnected = true; + } + else + { + if (disconnected) + { + points_list.emplace_back(); + cur_list = &points_list.back(); + if (!first_point) cur_list->push_back({last_x, last_y}); + disconnected = false; + } + cur_list->push_back({x, y}); + } + first_point = false; + }; + this->sample_points(curve, path_filler); + + return points_list; +} + +template +template +void ArrangementPainterOstream< + CGAL::Arr_rational_function_traits_2>:: + sample_points(const X_monotone_curve_2& curve, Lambda&& lambda) +{ + // TODO: cache maximum and minimal points for each curve, and include them + // in the sampled points + const QRectF viewport = this->viewportRect(); + qreal min_x = viewport.left(); + qreal max_x = viewport.right(); + + auto&& numer = curve._f.numer(); + auto&& denom = curve._f.denom(); + + auto eval_at = [&](auto&& x) { + return numer.evaluate(x) / denom.evaluate(x); + }; + + if ( // be conservative and prefer this branch to avoid zero division + curve.left_parameter_space_in_x() == ARR_INTERIOR && + curve.left_x().to_interval().second >= min_x) + { + min_x = curve.left_x().to_interval().second; + switch (curve.left_parameter_space_in_y()) + { + case ARR_INTERIOR: { + auto left_pt = curve.left().to_double(); + lambda(min_x, left_pt.second); + break; + } + case ARR_TOP_BOUNDARY: { + lambda(min_x, std::numeric_limits::infinity()); + break; + } + case ARR_BOTTOM_BOUNDARY: { + lambda(min_x, -std::numeric_limits::infinity()); + break; + } + default: { + CGAL_error(); + } + } + } + else if ( + curve.right_parameter_space_in_x() != ARR_INTERIOR || + min_x < curve.right_x().to_interval().first) + { + lambda(min_x, CGAL::to_double(eval_at(Rational{min_x}))); + } + else // outside of viewport + { + return; + } + + std::pair last_pt; + + if ( // be conservative and prefer this branch to avoid zero division + curve.right_parameter_space_in_x() == ARR_INTERIOR && + curve.right_x().to_interval().first <= max_x) + { + max_x = curve.right_x().to_interval().first; + switch (curve.right_parameter_space_in_y()) + { + case ARR_INTERIOR: { + last_pt = {max_x, curve.right().to_double().second}; + break; + } + case ARR_TOP_BOUNDARY: { + last_pt = {max_x, std::numeric_limits::infinity()}; + break; + } + case ARR_BOTTOM_BOUNDARY: { + last_pt = {max_x, -std::numeric_limits::infinity()}; + break; + } + default: { + CGAL_error(); + } + } + } + else if (max_x > min_x) + { + last_pt = {max_x, CGAL::to_double(eval_at(Rational{max_x}))}; + } + else // outside of viewport + { + return; + } + + static constexpr int dx_pixel = 1; + static constexpr int min_num_points = 20; + QLineF ux_line = this->getView()->transform().map(QLineF{0, 0, 1, 0}); + Rational dx = (CGAL::min)( + dx_pixel * Rational{1} / ux_line.length(), + Rational{max_x - min_x} / min_num_points); + + for (Rational cur_x = min_x + dx; cur_x < max_x - dx; cur_x += dx) + lambda(CGAL::to_double(cur_x), CGAL::to_double(eval_at(cur_x))); + + lambda(last_pt.first, last_pt.second); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(ArrangementPainterOstream) + +} // namespace Qt +} // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.h index ef9d34a7aad..33942b6d83a 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementPainterOstream.h @@ -1,11 +1,13 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Saurabh Singh +// Ahmed Essam #ifndef CGAL_QT_ARRANGEMENT_PAINTER_OSTREAM_H #define CGAL_QT_ARRANGEMENT_PAINTER_OSTREAM_H @@ -13,19 +15,11 @@ #include #include -// TODO: should be included in PainterOstream.h -#include #include -#include -#include -#include -#include -#include -#include - -#include "Utils.h" - -// #include +#include "ForwardDeclarations.h" +#include "GraphicsSceneMixin.h" +#include "Utils/Utils.h" +#include "Utils/IntersectCurves.h" class QPainter; @@ -33,19 +27,16 @@ namespace CGAL { namespace Qt { template < typename ArrTraits > -class ArrangementPainterOstreamBase : public QGraphicsSceneMixin +class ArrangementPainterOstreamBase : public GraphicsSceneMixin { public: // typedefs - typedef ArrTraits Traits; + typedef ArrTraits Traits; typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; typedef typename Kernel::Point_2 Point_2; typedef typename Kernel::Segment_2 Segment_2; typedef typename Kernel::Ray_2 Ray_2; typedef typename Kernel::Line_2 Line_2; - typedef typename Kernel::Triangle_2 Triangle_2; - typedef typename Kernel::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Kernel::Circle_2 Circle_2; public: /*! Constructor */ @@ -54,14 +45,8 @@ public: painterOstream( p, clippingRectangle ), qp( p ), convert( clippingRectangle ), - // scene( NULL ), - clippingRect( QRectF( ) ), // null rectangle - scale( 1.0 ) + clippingRect( QRectF( ) ) // null rectangle { - if ( p != 0 ) - { - this->scale = p->worldTransform( ).m11( ); - } } /*! Destructor (virtual) */ @@ -75,56 +60,24 @@ public: return *this; } - void setScene( QGraphicsScene* scene_ ) + void setScene( QGraphicsScene* scene_ ) override { - this->scene = scene_; + GraphicsSceneMixin::setScene(scene_); // set the clipping rectangle - if ( scene_ == NULL ) + if ( scene_ ) { - return; + this->clippingRect = this->viewportRect( ); + this->convert = Converter< Kernel >( this->clippingRect ); } - this->clippingRect = this->viewportRect( ); - this->convert = Converter< Kernel >( this->clippingRect ); } -#if 0 - void setScene( QGraphicsScene* scene_ ) - { - this->scene = scene_; - - // set the clipping rectangle - if ( scene_ == NULL ) - { - return; - } - this->clippingRect = this->getViewportRect( ); - } -#endif - -protected: // methods -#if 0 - QRectF getViewportRect( ) const - { - // assumes scene is not null and attached to exactly one view - QGraphicsView* view = this->scene->views( ).first( ); - QPointF p1 = view->mapToScene( 0, 0 ); - QPointF p2 = view->mapToScene( view->width( ), view->height( ) ); - QRectF clipRect = QRectF( p1, p2 ); - - return clipRect; - } -#endif - protected: // fields PainterOstream< Kernel > painterOstream; QPainter* qp; Converter< Kernel > convert; - // QGraphicsScene* scene; QRectF clippingRect; - double scale; - }; // class ArrangementPainterOstreamBase template < typename ArrTraits > @@ -153,9 +106,6 @@ public: // typedefs typedef typename Superclass::Segment_2 Segment_2; typedef typename Superclass::Ray_2 Ray_2; typedef typename Superclass::Line_2 Line_2; - typedef typename Superclass::Triangle_2 Triangle_2; - typedef typename Superclass::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Superclass::Circle_2 Circle_2; typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -169,45 +119,7 @@ public: virtual ~ArrangementPainterOstream() {} public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) - { - const Point_2& p1 = curve.source( ); - const Point_2& p2 = curve.target( ); - Segment_2 seg( p1, p2 ); - - // skip segments outside our view - QRectF seg_bb = this->convert( seg.bbox( ) ); - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.intersects( seg_bb ) ) - { - return *this; - } - - this->painterOstream << seg; - return *this; - } - - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - QPointF qpt = this->convert( p ); - // clip the point if possible - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.contains( qpt ) ) - { - return *this; - } - - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - return *this; - } + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); template < typename T > ArrangementPainterOstream& operator<<( const T& p ) @@ -231,9 +143,6 @@ public: // typedefs typedef typename Superclass::Segment_2 Segment_2; typedef typename Superclass::Ray_2 Ray_2; typedef typename Superclass::Line_2 Line_2; - typedef typename Superclass::Triangle_2 Triangle_2; - typedef typename Superclass::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Superclass::Circle_2 Circle_2; typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -247,39 +156,7 @@ public: virtual ~ArrangementPainterOstream() {} public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) - { - for (typename X_monotone_curve_2::Subcurve_const_iterator it = - curve.subcurves_begin(); - it != curve.subcurves_end(); ++it) - { - this->painterOstream << *it; - } - // TODO: implement polyline painting -#if 0 - const Point_2& p1 = curve.source( ); - const Point_2& p2 = curve.target( ); - Segment_2 seg( p1, p2 ); - this->painterOstream << seg; -#endif - return *this; - } - - // cloned from segtraits painter - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - QPointF qpt = this->convert( p ); - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - return *this; - } + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); template < typename T > ArrangementPainterOstream& operator<<( const T& p ) @@ -303,9 +180,6 @@ public: // typedefs typedef typename Superclass::Segment_2 Segment_2; typedef typename Superclass::Ray_2 Ray_2; typedef typename Superclass::Line_2 Line_2; - typedef typename Superclass::Triangle_2 Triangle_2; - typedef typename Superclass::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Superclass::Circle_2 Circle_2; typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; typedef typename Traits::Construct_x_monotone_curve_2 @@ -335,8 +209,7 @@ public: /*! Constructor */ ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = QRectF()) : Superclass( p, clippingRectangle ), - //intersect_2( this->traits.intersect_2_object( ) ), - // Why doesn't this work? + intersect_2( &this->traits ), construct_x_monotone_curve_2(this-> traits.construct_x_monotone_curve_2_object()) { } @@ -345,143 +218,7 @@ public: virtual ~ArrangementPainterOstream() {} public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) - { - CGAL::Bbox_2 bb = curve.bbox( ); - QRectF qbb = this->convert( bb ); - // quick cull - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.intersects( qbb ) ) - { - //std::cout << "quick culled curve" << std::endl; - return *this; - } - -#if 0 - std::cout << "bottom: (" - << this->clippingRect.bottomLeft( ).x( ) - << " " - << this->clippingRect.bottomLeft( ).y( ) - << " " - << this->clippingRect.bottomRight( ).x( ) - << " " - << this->clippingRect.bottomRight( ).y( ) - << ")" - << std::endl; -#endif - - if ( this->clippingRect.isValid( ) ) - { - std::vector< X_monotone_curve_2 > visibleParts; - if ( this->clippingRect.contains( qbb ) ) - { - visibleParts.push_back( curve ); - } - else - { - visibleParts = this->visibleParts( curve ); - } - for ( unsigned int i = 0; i < visibleParts.size( ); ++i ) - { - X_monotone_curve_2 subcurve = visibleParts[ i ]; - int n; - if ( this->scene == NULL ) - n = 100; // TODO: get an adaptive approximation - else - { - QGraphicsView* view = this->scene->views( ).first( ); - int xmin, xmax; - xmin = view->mapFromScene( bb.xmin( ), bb.ymin( ) ).x( ); - xmax = view->mapFromScene( bb.xmax( ), bb.ymin( ) ).x( ); - n = xmax - xmin; - } - if ( n == 0 ) - { - return *this; - } - - std::pair* app_pts = - new std::pair[n + 1]; - std::pair* end_pts = - subcurve.polyline_approximation(n, app_pts); - std::pair* p_curr = app_pts; - std::pair* p_next = p_curr + 1; - int count = 0; - do - { - QPointF p1( p_curr->first, p_curr->second ); - QPointF p2( p_next->first, p_next->second ); -#if 0 - Segment_2 seg( p1, p2 ); - this->painterOstream << seg; -#endif - this->qp->drawLine( p1, p2 ); - p_curr++; - p_next++; - ++count; - } - while ( p_next != end_pts ); - } - } - else - { // draw the whole curve - int n; - if ( this->scene == NULL ) - n = 100; // TODO: get an adaptive approximation - else - { - QGraphicsView* view = this->scene->views( ).first( ); - int xmin, xmax; - xmin = view->mapFromScene( bb.xmin( ), bb.ymin( ) ).x( ); - xmax = view->mapFromScene( bb.xmax( ), bb.ymin( ) ).x( ); - n = xmax - xmin; - } - if ( n == 0 ) - { - return *this; - } - - std::pair* app_pts = new std::pair[n + 1]; - std::pair* end_pts = - curve.polyline_approximation(n, app_pts); - std::pair* p_curr = app_pts; - std::pair* p_next = p_curr + 1; - int count = 0; - do - { - QPointF p1( p_curr->first, p_curr->second ); - QPointF p2( p_next->first, p_next->second ); -#if 0 - Segment_2 seg( p1, p2 ); - this->painterOstream << seg; -#endif - this->qp->drawLine( p1, p2 ); - p_curr++; - p_next++; - ++count; - } - while ( p_next != end_pts ); - //std::cout << count << " approximation points" << std::endl; - } - - return *this; - } - - // cloned from segtraits painter - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - QPointF qpt = this->convert( p ); - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - return *this; - } + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); template < typename T > ArrangementPainterOstream& operator<<( const T& p ) @@ -493,174 +230,52 @@ public: // methods protected: // methods // Returns subcurves of curve that are actually visible in the view. // Assumes that clippingRect is valid. - std::vector< X_monotone_curve_2 > visibleParts( X_monotone_curve_2 curve ) - { - // see if we intersect the bottom edge of the viewport - Intersect_2 intersect_2 = this->traits.intersect_2_object( ); - Point_2 bottomLeft = this->convert( this->clippingRect.bottomLeft( ) ); - Point_2 bottomRight = this->convert( this->clippingRect.bottomRight( ) ); - Point_2 topLeft = this->convert( this->clippingRect.topLeft( ) ); - Point_2 topRight = this->convert( this->clippingRect.topRight( ) ); - X_monotone_curve_2 bottom = - this->construct_x_monotone_curve_2( bottomLeft, bottomRight ); - X_monotone_curve_2 left = - this->construct_x_monotone_curve_2( bottomLeft, topLeft ); - X_monotone_curve_2 top = - this->construct_x_monotone_curve_2( topLeft, topRight ); - X_monotone_curve_2 right = - this->construct_x_monotone_curve_2( topRight, bottomRight ); - - std::vector< CGAL::Object > bottomIntersections; - std::vector< CGAL::Object > leftIntersections; - std::vector< CGAL::Object > topIntersections; - std::vector< CGAL::Object > rightIntersections; - std::vector< CGAL::Object > intersections; - - intersect_2( bottom, curve, std::back_inserter( bottomIntersections ) ); - intersect_2( left, curve, std::back_inserter( leftIntersections ) ); - intersect_2( top, curve, std::back_inserter( topIntersections ) ); - intersect_2( right, curve, std::back_inserter( rightIntersections ) ); - // int total = bottomIntersections.size( ) - // + leftIntersections.size( ) - // + topIntersections.size( ) - // + rightIntersections.size( ); - - intersect_2( bottom, curve, std::back_inserter( intersections ) ); - intersect_2( left, curve, std::back_inserter( intersections ) ); - intersect_2( top, curve, std::back_inserter( intersections ) ); - intersect_2( right, curve, std::back_inserter( intersections ) ); - - this->filterIntersectionPoints( intersections ); - //std::cout << "total intersections: " << intersections.size( ) - // << std::endl; - //this->printIntersectResult( intersections ); - - Point_2 leftEndpt = curve.source( ); - Point_2 rightEndpt = curve.target( ); - if ( leftEndpt.x( ) > rightEndpt.x( ) ) - { - std::swap( leftEndpt, rightEndpt ); - } - QPointF qendpt1 = this->convert( leftEndpt ); - QPointF qendpt2 = this->convert( rightEndpt ); - std::list< Point_2 > pointList; - for ( unsigned int i = 0; i < intersections.size( ); ++i ) - { - CGAL::Object o = intersections[ i ]; - std::pair< Intersection_point_2, Multiplicity > pair; - if ( CGAL::assign( pair, o ) ) - { - Point_2 pt = pair.first; - pointList.push_back( pt ); - } - } - bool includeLeftEndpoint = this->clippingRect.contains( qendpt1 ); - bool includeRightEndpoint = this->clippingRect.contains( qendpt2 ); - if ( includeLeftEndpoint ) - pointList.push_front( leftEndpt ); - if ( includeRightEndpoint ) - pointList.push_back( rightEndpt ); - - Construct_x_monotone_subcurve_2< Traits > construct_x_monotone_subcurve_2; - std::vector< X_monotone_curve_2 > clippings; - typename std::list< Point_2 >::iterator pointListItr = pointList.begin( ); - for ( unsigned int i = 0; i < pointList.size( ); i += 2 ) - { - Point_2 p1 = *pointListItr++; - Point_2 p2 = *pointListItr++; - X_monotone_curve_2 subcurve = - construct_x_monotone_subcurve_2( curve, p1, p2 ); - clippings.push_back( subcurve ); - } - -#if 0 - // std::cout << "pointList size: " << pointList.size( ) << std::endl; - // if ( intersections.size( ) % 2 == 0 ) - // { - // // either both curve endpoints are in view or both are out - // if ( this->clippingRect.contains( qendpt1 ) ) - // { - // if ( this->clippingRect.contains( qendpt2 ) ) - // { - // std::cout << "both endpoints are in view" << std::endl; - // } - // } - // else if ( !this->clippingRect.contains( qendpt2 ) ) - // { - // std::cout << "both endpoints are out of view" << std::endl; - // } - // } - // else - // { // one curve endpoint is in view - // if ( this->clippingRect.contains( qendpt1 ) ) - // { - // std::cout << "left endpoint is in view" << std::endl; - // } - // else if ( this->clippingRect.contains( qendpt2 ) ) - // { - // std::cout << "right endpoint is in view" << std::endl; - // } - // } - - std::vector< X_monotone_curve_2 > res; - res.push_back( curve ); - return res; -#endif - return clippings; - } + std::vector< X_monotone_curve_2 > visibleParts( X_monotone_curve_2 curve ); // keep only the intersection points ie. throw out overlapping curve segments - void filterIntersectionPoints( std::vector< CGAL::Object >& res ) - { - std::vector< std::pair< Intersection_point_2, Multiplicity > > tmp; - - // filter out the non-intersection point results - for ( unsigned int i = 0; i < res.size( ); ++i ) - { - CGAL::Object obj = res[ i ]; - std::pair< Intersection_point_2, Multiplicity > pair; - if ( CGAL::assign( pair, obj ) ) - { - tmp.push_back( pair ); - } - } - res.clear( ); - - // sort the intersection points by x-coord - Compare_intersection_point_result compare_intersection_point_result; - std::sort( tmp.begin( ), tmp.end( ), compare_intersection_point_result ); - - // box up the sorted elements - for ( unsigned int i = 0; i < tmp.size( ); ++i ) - { - std::pair< Intersection_point_2, Multiplicity > pair = tmp[ i ]; - CGAL::Object o = CGAL::make_object( pair ); - res.push_back( o ); - } - } - - void printIntersectResult( const std::vector< CGAL::Object >& res ) - { - for ( std::vector< CGAL::Object >::const_iterator it = res.begin( ); - it != res.end( ); ++it ) - { - CGAL::Object obj = *it; - std::pair< Intersection_point_2, Multiplicity > pair; - if ( CGAL::assign( pair, obj ) ) - { - Point_2 pt = pair.first; - /* QPointF qpt = */ this->convert( pt ); - // std::cout << "(" << pt.x( ) << " " << pt.y( ) < ")" << std::endl; - } - } - } + void filterIntersectionPoints( std::vector< CGAL::Object >& res ); protected: // members Traits traits; - //Intersect_2 intersect_2; + Intersect_curves intersect_2; Construct_x_monotone_curve_2 construct_x_monotone_curve_2; }; +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class ArrangementPainterOstream> : + public ArrangementPainterOstreamBase> +{ + +public: // typedefs + typedef CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits> + Traits; + typedef ArrangementPainterOstreamBase< Traits > Superclass; + typedef typename Superclass::Point_2 Point_2; + typedef typename Traits::Curve_2 Curve_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; + +public: + /*! Constructor */ + ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = QRectF()) : + Superclass( p, clippingRectangle ) + { } + + /*! Destructor (virtual) */ + virtual ~ArrangementPainterOstream() {} + +public: // methods + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); + + std::vector> + getPoints(const X_monotone_curve_2& curve); +}; + template < typename Kernel_ > class ArrangementPainterOstream< CGAL::Arr_linear_traits_2< Kernel_ > >: public ArrangementPainterOstreamBase< CGAL::Arr_linear_traits_2< Kernel_ > > @@ -673,9 +288,6 @@ public: // typedefs typedef typename Superclass::Segment_2 Segment_2; typedef typename Superclass::Ray_2 Ray_2; typedef typename Superclass::Line_2 Line_2; - typedef typename Superclass::Triangle_2 Triangle_2; - typedef typename Superclass::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Superclass::Circle_2 Circle_2; typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; @@ -689,68 +301,7 @@ public: virtual ~ArrangementPainterOstream() {} public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) - { - if ( curve.is_segment( ) ) - { - Segment_2 seg = curve.segment( ); - - // skip segments outside our view - QRectF seg_bb = this->convert( seg.bbox( ) ); - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.intersects( seg_bb ) ) - { - return *this; - } - - this->painterOstream << seg; - } - else if ( curve.is_ray( ) ) - { - Ray_2 ray = curve.ray( ); - QLineF qseg = this->convert( ray ); - if ( qseg.isNull( ) ) - { // it's out of view - return *this; - } - Segment_2 seg = this->convert( qseg ); - this-> painterOstream << seg; - } - else // curve.is_line( ) - { - Line_2 line = curve.line( ); - QLineF qseg = this->convert( line ); - if ( qseg.isNull( ) ) - { // it's out of view - return *this; - } - Segment_2 seg = this->convert( qseg ); - this-> painterOstream << seg; - } - return *this; - } - - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - QPointF qpt = this->convert( p ); - // clip the point if possible - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.contains( qpt ) ) - { - return *this; - } - - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - return *this; - } + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); template < typename T > ArrangementPainterOstream& operator<<( const T& p ) @@ -760,72 +311,7 @@ public: // methods } }; -template < typename CircularKernel > -class ArrangementPainterOstream< CGAL::Arr_circular_arc_traits_2< - CircularKernel > >: - public ArrangementPainterOstreamBase< CGAL::Arr_circular_arc_traits_2< - CircularKernel > > -{ -public: - typedef CircularKernel Kernel; - typedef CGAL::Arr_circular_arc_traits_2< Kernel > Traits; - typedef ArrangementPainterOstreamBase< Traits > Superclass; - typedef typename Superclass::Point_2 Point_2; - typedef typename Superclass::Segment_2 Segment_2; - typedef typename Superclass::Ray_2 Ray_2; - typedef typename Superclass::Line_2 Line_2; - typedef typename Superclass::Triangle_2 Triangle_2; - typedef typename Superclass::Iso_rectangle_2 Iso_rectangle_2; - typedef typename Superclass::Circle_2 Circle_2; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; -public: - /*! Constructor */ - ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = QRectF()): - Superclass( p, clippingRectangle ) - { } - /*! Destructor (virtual) */ - virtual ~ArrangementPainterOstream() {} - -public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) - { - this->painterOstream << curve; - return *this; - } - - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - QPointF qpt = this->convert( p ); - // clip the point if possible - if ( this->clippingRect.isValid( ) && - ! this->clippingRect.contains( qpt ) ) - { - return *this; - } - - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - return *this; - } - - template < typename T > - ArrangementPainterOstream& operator<<( const T& p ) - { - (*(static_cast< Superclass* >(this)) << p); - return *this; - } -}; - -#if 0 template < typename Coefficient_ > class ArrangementPainterOstream< CGAL::Arr_algebraic_segment_traits_2< Coefficient_ > >: @@ -840,140 +326,50 @@ public: typedef typename Traits::CKvA_2 CKvA_2; typedef typename Traits::Point_2 Point_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef std::pair Coord_2; + typedef std::vector Coord_vec_2; public: /*! Constructor */ - ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = QRectF()): - Superclass( p, clippingRectangle ) - { } + ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = QRectF()) : + Superclass(p, clippingRectangle) + { + } + + void setScene(QGraphicsScene* scene_) override + { + Superclass::setScene(scene_); + this->setupFacade(); + } /*! Destructor (virtual) */ virtual ~ArrangementPainterOstream() {} public: // methods - ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ) + + ArrangementPainterOstream& operator<<( const X_monotone_curve_2& curve ); + + // more efficient than repeatedly calling operator<< since we will only call + // remapFacadePainter once + template + void paintEdges(EdgesIterator first, EdgesIterator last) { - //std::cout << "paint curve stub (alg traits)" << std::endl; - typedef Curve_renderer_facade Facade; - typedef std::pair< int, int > Coord_2; - typedef std::vector< Coord_2 > Coord_vec_2; - this->setupFacade( ); - - boost::optional < Coord_2 > p1, p2; - std::list points; - - Facade::instance().draw( curve, points, &p1, &p2 ); - if(points.empty()) - return *this; - - // QPainter *ppnt = this->qp; - QGraphicsView* view = this->scene->views( ).first( ); - // int height = view->height(); - // std::cerr << ws.width() << " and " << ws.height() << "\n"; - typename std::list::const_iterator lit = points.begin(); - //ppnt->moveTo((*p1).first, height - (*p1).second); - while(lit != points.end()) { - - const Coord_vec_2& vec = *lit; - typename Coord_vec_2::const_iterator vit = vec.begin(); - //std::cerr << "(" << vit->first << "; " << vit->second << ")\n"; - // if(lit == points.begin() &&*/ vit != vec.end()) { - // ppnt->lineTo(vit->first, height - vit->second); - // vit++; - // } -#if 0 - if(vit != vec.end()) - ppnt->moveTo(vit->first, height - vit->second); - - while(vit != vec.end()) { - ppnt->lineTo(vit->first, height - vit->second); - vit++; - //std::cerr << "(" << vit->e0 << "; " << vit->e1 << "\n"; - } - lit++; -#endif - QPainterPath path; - QPoint coord( vit->first, vit->second ); - QPointF qpt = view->mapToScene( coord ); - if ( vit != vec.end() ) - { - path.moveTo( qpt ); - } - while ( vit != vec.end() ) - { - path.lineTo( qpt ); - vit++; - coord = QPoint( vit->first, vit->second ); - qpt = view->mapToScene( coord ); - //std::cout << vit->first << " " << vit->second << std::endl; - } - this->qp->drawPath( path ); - - lit++; - } - //ppnt->lineTo((*p2).first, height - (*p2).second); - -#if 0 - QPen old_pen = ppnt->pen(); - ppnt->setPen(QPen(Qt::NoPen)); // avoid drawing outlines - // draw with the current brush attributes - - //std::cerr << "endpts1: (" << (*p1).first << "; " << (*p1).second << "\n"; - //std::cerr << "endpts2: (" << (*p2).first << "; " << (*p2).second << "\n"; - - unsigned sz = CGAL_REND_PT_RADIUS; - ppnt->drawEllipse((*p1).first - sz, height-(*p1).second - sz, sz*2, sz*2); - ppnt->drawEllipse((*p2).first - sz, height-(*p2).second - sz, sz*2, sz*2); - ppnt->setPen(old_pen); -#endif - - return *this; - } - - ArrangementPainterOstream& operator<<( const Point_2& p ) - { - typedef Curve_renderer_facade Facade; - std::pair< int, int > coord; - //std::cout << "draw point stub" << std::endl; - - this->setupFacade( ); - - if(!Facade::instance().draw(p, coord)) { - return *this; - } - else + this->qp->save(); + this->remapFacadePainter(); + for (auto it = first; it != last; ++it) { - //std::cout << coord.first << " " << coord.second << std::endl; - QPoint coords( coord.first, coord.second ); - QGraphicsView* view = this->scene->views( ).first( ); - QPointF qpt = view->mapToScene( coords ); - - QPen savePen = this->qp->pen( ); - this->qp->setBrush( QBrush( savePen.color( ) ) ); - double radius = savePen.width( ) / 2.0; - radius /= this->scale; - - this->qp->drawEllipse( qpt, radius, radius ); - - this->qp->setBrush( QBrush( ) ); - this->qp->setPen( savePen ); - + X_monotone_curve_2 curve = it->curve(); + this->paintCurve(curve); } -#if 0 - - QPainter *ppnt = &ws.get_painter(); - QPen old_pen = ppnt->pen(); - ppnt->setPen(QPen(Qt::NoPen)); - - unsigned sz = CGAL_REND_PT_RADIUS; - ppnt->drawEllipse(coord.first - sz, ws.height() - coord.second - sz, - sz*2, sz*2); - ppnt->setPen(old_pen); -#endif - - return *this; + this->qp->restore(); } + // Maybe move these functions to someplace else? + std::vector getPointsList(const X_monotone_curve_2& curve); + QTransform getPointsListMapping(); + QTransform getPointsListMapping(const QTransform& worldTransform); + void setupFacade(); + template < typename T > ArrangementPainterOstream& operator<<( const T& p ) { @@ -982,16 +378,40 @@ public: // methods } protected: - void setupFacade( ) - { - typedef Curve_renderer_facade Facade; - QGraphicsView* view = this->scene->views( ).first( ); - QRectF viewport = this->viewportRect( ); - CGAL::Bbox_2 bbox = this->convert( viewport ).bbox( ); - Facade::setup(bbox, view->width(), view->height()); - } + void paintCurve(const X_monotone_curve_2& curve); + void remapFacadePainter(); +}; + +template +class ArrangementPainterOstream< + CGAL::Arr_rational_function_traits_2> : + public ArrangementPainterOstreamBase< + CGAL::Arr_rational_function_traits_2> +{ +public: + typedef AlgebraicKernel_d_1_ AlgebraicKernel_d_1; + typedef Arr_rational_function_traits_2 + Traits; + typedef typename Traits::Rational Rational; + typedef ArrangementPainterOstreamBase Superclass; + typedef ArrangementPainterOstream Self; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef std::pair Coord_2; + typedef std::vector Coord_vec_2; + +public: + ArrangementPainterOstream(QPainter* p, QRectF clippingRectangle = {}) : + Superclass(p, clippingRectangle) + { + } + + Self& operator<<(const X_monotone_curve_2& curve); + std::vector getPointsList(const X_monotone_curve_2& curve); + +protected: + template + void sample_points(const X_monotone_curve_2& curve, Lambda&& lambda); }; -#endif } // namespace Qt } // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementSegmentInputCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementSegmentInputCallback.h deleted file mode 100644 index 320505f6759..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementSegmentInputCallback.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef ARRANGEMENT_SEGMENT_INPUT_CALLBACK_H -#define ARRANGEMENT_SEGMENT_INPUT_CALLBACK_H - -#include -//#include -//#include -//#include -#include -#include - -#include "GraphicsViewSegmentInput.h" -#include "Utils.h" - -template < typename Arr_ > -class ArrangementSegmentInputCallback: - public CGAL::Qt::GraphicsViewSegmentInput< - typename ArrTraitsAdaptor< typename Arr_::Geometry_traits_2 >::Kernel > -{ -public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef CGAL::Qt::GraphicsViewSegmentInput< Kernel > Superclass; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Construct_x_monotone_curve_2 - Construct_x_monotone_curve_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::FT FT; - - ArrangementSegmentInputCallback( Arrangement* arrangement_, QObject* parent); - void processInput( CGAL::Object ); - void setScene( QGraphicsScene* scene_ ); - -protected: - Point_2 snapPoint( QGraphicsSceneMouseEvent* event ); - - Arrangement* arrangement; - Construct_x_monotone_curve_2 construct_x_monotone_curve_2; - SnapToArrangementVertexStrategy< Arrangement > snapToVertexStrategy; - SnapToGridStrategy< Kernel > snapToGridStrategy; -}; // class ArrangementSegmentInputCallback - -template < typename Arr_ > -ArrangementSegmentInputCallback< Arr_ >:: -ArrangementSegmentInputCallback( Arrangement* arrangement_, QObject* parent ): - Superclass( parent ), - arrangement( arrangement_ ) -{ - this->snapToVertexStrategy.setArrangement( arrangement_ ); - - QObject::connect( this, SIGNAL( generate( CGAL::Object ) ), - this, SLOT( processInput( CGAL::Object ) ) ); -} - -template < typename Arr_ > -void -ArrangementSegmentInputCallback< Arr_ >:: -processInput( CGAL::Object o ) -{ - Segment_2 segment; - if ( CGAL::assign( segment, o ) ) - { - // insert a segment - Point_2 p1 = segment.source( ); - Point_2 p2 = segment.target( ); - Curve_2 curve = this->construct_x_monotone_curve_2( p1, p2 ); - CGAL::insert( *( this->arrangement ), curve ); - } - - Q_EMIT CGAL::Qt::GraphicsViewInput::modelChanged( ); -} - -template < typename Arr_ > -void -ArrangementSegmentInputCallback< Arr_ >::setScene( QGraphicsScene* scene_ ) -{ - this->Superclass::setScene( scene_ ); - this->snapToVertexStrategy.setScene( scene_ ); - this->snapToGridStrategy.setScene( scene_ ); -} - -template < typename Arr_ > -typename ArrangementSegmentInputCallback< Arr_ >::Point_2 -ArrangementSegmentInputCallback< Arr_ >:: -snapPoint( QGraphicsSceneMouseEvent* event ) -{ - if ( this->snapToGridEnabled ) - { - return this->snapToGridStrategy.snapPoint( event ); - } - else if ( this->snappingEnabled ) - { - return this->snapToVertexStrategy.snapPoint( event ); - } - else - { - return this->convert( event->scenePos( ) ); - } -} - -#endif // ARRANGEMENT_SEGMENT_INPUT_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypes.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypes.h index fdde42cf518..417ffbd3fd0 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypes.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypes.h @@ -1,75 +1,55 @@ -// Copyright (c) 2005,2012 Tel-Aviv University (Israel). +// Copyright (c) 2005, 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Baruch Zukerman -// Alex Tsui +// Author(s): Baruch Zukerman +// Alex Tsui +// Saurabh Singh +// Ahmed Essam #ifndef ARRANGEMENT_DEMO_TYPES_H #define ARRANGEMENT_DEMO_TYPES_H -#include - -/* -#include -#include -#include -*/ - +#include #include #include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Coordinate related typedef - using inexact number type -typedef float Coord_type; -typedef CGAL::Cartesian Coord_kernel; -typedef Coord_kernel::Point_2 Coord_point; -typedef Coord_kernel::Segment_2 Coord_segment; -typedef Coord_kernel::Circle_2 Coord_circle; - - -typedef CGAL::Polygon_2 My_polygon; - // polygon is usefull for filling faces - -#ifdef CGAL_USE_GMP - #include - typedef CGAL::Gmpq NT; -#else - #include - #include - typedef CGAL::Quotient NT; +#ifdef CGAL_USE_CORE + #include + #include + #include + #include + #include + #include + #include #endif -// instead of -//typedef CGAL::Cartesian Kernel; -// workaround for VC++ -struct Kernel : public CGAL::Cartesian {}; +#include "RationalTypes.h" + +#include + +// avoid polluting global namespace +// caused multiple bugs before! +namespace demo_types +{ +struct DemoTypes +{ class Face_with_color : public CGAL::Arr_face_base { QColor m_color; bool m_visited; public: - Face_with_color() : CGAL::Arr_face_base(), m_color(), m_visited(false) { } + Face_with_color() : + CGAL::Arr_face_base(), m_color(::Qt::white), m_visited(false) + { + } QColor color() const { return m_color; } void set_color(const QColor& c) { m_color = c; } @@ -79,10 +59,10 @@ public: template class Dcel : - public CGAL::Arr_dcel_base, - CGAL::Arr_halfedge_base< - typename Traits::X_monotone_curve_2>, - Face_with_color> + public CGAL::Arr_dcel_base< + CGAL::Arr_vertex_base, + CGAL::Arr_halfedge_base, + Face_with_color> { public: /*! \struct @@ -93,225 +73,98 @@ public: { typedef Dcel other; }; - - // CREATION - Dcel() {} }; +// use same rational type across arrangements +// less specializations, and makes PointSnapper untemplated +typedef typename RationalTypes::Rational Rational; +typedef typename RationalTypes::Rat_kernel Rat_kernel; +typedef typename RationalTypes::Rat_point_2 Rat_point_2; + // Segments: -typedef CGAL::Arr_segment_traits_2 Seg_traits; -typedef Seg_traits::Curve_2 Arr_seg_2; -typedef Seg_traits::X_monotone_curve_2 Arr_xseg_2; -typedef Seg_traits::Point_2 Arr_seg_point_2; +typedef CGAL::Arr_segment_traits_2 Seg_traits; typedef Dcel Seg_dcel; typedef CGAL::Arrangement_with_history_2 Seg_arr; -typedef Seg_arr::Halfedge Seg_halfedge; -typedef Seg_arr::Halfedge_handle Seg_halfedge_handle; -typedef Seg_arr::Face_handle Seg_face_handle; -typedef Seg_arr::Ccb_halfedge_circulator - Seg_ccb_halfedge_circulator; -typedef Seg_arr::Hole_iterator Seg_holes_iterator; -typedef Seg_arr::Face_iterator Seg_face_iterator; -typedef std::list Arr_seg_list; -typedef Arr_seg_list::const_iterator Arr_seg_const_iter; -typedef Arr_seg_list::iterator Arr_seg_iter; - - -// point location -typedef CGAL::Arr_trapezoid_ric_point_location - Seg_trap_point_location; -typedef CGAL::Arr_simple_point_location - Seg_simple_point_location; -typedef CGAL::Arr_walk_along_line_point_location - Seg_walk_point_location; -typedef CGAL::Arr_landmarks_point_location - Seg_lanmarks_point_location; // Polyline typedef CGAL::Arr_polyline_traits_2 Pol_traits; - -typedef Pol_traits::Curve_2 Arr_pol_2; -typedef Pol_traits::X_monotone_curve_2 Arr_xpol_2; - -typedef Pol_traits::Point_2 Arr_pol_point_2; typedef Dcel Pol_dcel; typedef CGAL::Arrangement_with_history_2 Pol_arr; -typedef Pol_arr::Halfedge_handle Pol_halfedge_handle; -typedef Pol_arr::Face_handle Pol_face_handle; -typedef Pol_arr::Ccb_halfedge_circulator - Pol_ccb_halfedge_circulator; -typedef Pol_arr::Hole_iterator Pol_holes_iterator; -typedef Pol_arr::Halfedge Pol_halfedge; -typedef Pol_arr::Face_iterator Pol_face_iterator; - -typedef std::list Arr_pol_list; -typedef Arr_pol_list::const_iterator Arr_pol_const_iter; -typedef Arr_pol_list::iterator Arr_pol_iter; - -// point location -typedef CGAL::Arr_trapezoid_ric_point_location - Pol_trap_point_location; -typedef CGAL::Arr_simple_point_location - Pol_simple_point_location; -typedef CGAL::Arr_walk_along_line_point_location - Pol_walk_point_location; -typedef CGAL::Arr_landmarks_point_location - Pol_lanmarks_point_location; - - -// Conics - -#ifdef CGAL_USE_CORE - -#include - -typedef CGAL::CORE_algebraic_number_traits Nt_traits; -typedef Nt_traits::Rational Rational; -typedef Nt_traits::Algebraic Algebraic; -typedef CGAL::Cartesian Rat_kernel; -typedef CGAL::Cartesian Alg_kernel; - -// instead of -typedef CGAL::Arr_conic_traits_2 - Conic_traits; -// workaround for VC++ -/* -struct Conic_traits: public CGAL::Arr_conic_traits_2 {}; -*/ - -typedef Conic_traits::Curve_2 Arr_conic_2; -typedef Conic_traits::Rat_point_2 Rat_point_2; -typedef Conic_traits::Rat_segment_2 Rat_segment_2; -typedef Conic_traits::Rat_circle_2 Rat_circle_2; -typedef Conic_traits::Rat_line_2 Rat_line_2; - -typedef Conic_traits::X_monotone_curve_2 Arr_xconic_2; -typedef Conic_traits::Point_2 Arr_conic_point_2; -typedef Dcel Conic_dcel; -typedef CGAL::Arrangement_with_history_2 - Conic_arr; -typedef Conic_arr::Halfedge_handle Conic_halfedge_handle; -typedef Conic_arr::Face_handle Conic_face_handle; -typedef Conic_arr::Ccb_halfedge_circulator - Conic_ccb_halfedge_circulator; -typedef Conic_arr::Hole_iterator Conic_holes_iterator; -//typedef CGAL::Arr_file_scanner Arr_scanner; -typedef Conic_arr::Halfedge Conic_halfedge; -typedef Conic_arr::Face_iterator Conic_face_iterator; - -typedef std::list Arr_xconic_list; -typedef Arr_xconic_list::const_iterator Arr_xconic_const_iter; -typedef Arr_xconic_list::iterator Arr_xconic_iter; - -// point location -typedef CGAL::Arr_trapezoid_ric_point_location - Conic_trap_point_location; -typedef CGAL::Arr_simple_point_location - Conic_simple_point_location; -typedef CGAL::Arr_walk_along_line_point_location - Conic_walk_point_location; -typedef CGAL::Arr_landmarks_point_location - Conic_lanmarks_point_location; - -typedef Nt_traits::Integer Coefficient; -typedef CGAL::Arr_algebraic_segment_traits_2 Alg_seg_traits; -typedef Dcel< Alg_seg_traits > Alg_seg_dcel; -typedef CGAL::Arrangement_with_history_2< Alg_seg_traits, Alg_seg_dcel > - Alg_seg_arr; - -#endif // Linear: -typedef CGAL::Arr_linear_traits_2 Lin_traits; -typedef Lin_traits::Curve_2 Arr_lin_2; -typedef Lin_traits::X_monotone_curve_2 Arr_xlin_2; -typedef Lin_traits::Point_2 Arr_lin_point_2; +typedef CGAL::Arr_linear_traits_2 Lin_traits; typedef Dcel Lin_dcel; typedef CGAL::Arrangement_with_history_2 Lin_arr; -typedef Lin_arr::Halfedge Lin_halfedge; -typedef Lin_arr::Halfedge_handle Lin_halfedge_handle; -typedef Lin_arr::Face_handle Lin_face_handle; -typedef Lin_arr::Ccb_halfedge_circulator - Lin_ccb_halfedge_circulator; -typedef Lin_arr::Hole_iterator Lin_holes_iterator; -typedef Lin_arr::Face_iterator Lin_face_iterator; -typedef std::list Arr_lin_list; -typedef Arr_lin_list::const_iterator Arr_lin_const_iter; -typedef Arr_lin_list::iterator Arr_lin_iter; -//point location -typedef CGAL::Arr_trapezoid_ric_point_location - Lin_trap_point_location; -typedef CGAL::Arr_simple_point_location - Lin_simple_point_location; -typedef CGAL::Arr_walk_along_line_point_location - Lin_walk_point_location; -typedef CGAL::Arr_landmarks_point_location - Lin_landmarks_point_location; +#ifdef CGAL_USE_CORE + typedef CGAL::CORE_algebraic_number_traits Core_nt_traits; + typedef Core_nt_traits::Integer Core_integer; + typedef Core_nt_traits::Rational Core_rational; + typedef Core_nt_traits::Algebraic Core_algebraic; + typedef CGAL::Cartesian Core_rat_kernel; + typedef CGAL::Cartesian Core_alg_kernel; + // Conics + typedef CGAL::Arr_conic_traits_2< + Core_rat_kernel, Core_alg_kernel, Core_nt_traits> + Conic_traits; -#include -#include + typedef Dcel Conic_dcel; + typedef CGAL::Arrangement_with_history_2 + Conic_arr; + // Algebraic + typedef CGAL::Arr_algebraic_segment_traits_2 + Alg_seg_traits; + typedef Dcel Alg_seg_dcel; + typedef CGAL::Arrangement_with_history_2 + Alg_seg_arr; + // Bezier + typedef CGAL::Arr_Bezier_curve_traits_2< + Core_rat_kernel, Core_alg_kernel, Core_nt_traits> + Bezier_traits; + typedef Dcel Bezier_dcel; + typedef CGAL::Arrangement_with_history_2 + Bezier_arr; -// Circular arcs: -typedef CGAL::Exact_circular_kernel_2 CircularKernel; -typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > Arc_traits; -typedef Arc_traits::Curve_2 Arr_arc_2; -typedef Arc_traits::X_monotone_curve_2 Arr_xarc_2; -typedef Arc_traits::Point_2 Arr_arc_point_2; -typedef Dcel Arc_dcel; -typedef CGAL::Arrangement_with_history_2 - Arc_arr; -typedef Arc_arr::Halfedge Arc_halfedge; -typedef Arc_arr::Halfedge_handle Arc_halfedge_handle; -typedef Arc_arr::Face_handle Arc_face_handle; -typedef Arc_arr::Ccb_halfedge_circulator - Arc_ccb_halfedge_circulator; -typedef Arc_arr::Hole_iterator Arc_holes_iterator; -typedef Arc_arr::Face_iterator Arc_face_iterator; -typedef std::list Arr_arc_list; -typedef Arr_arc_list::const_iterator Arr_arc_const_iter; -typedef Arr_arc_list::iterator Arr_arc_iter; + // Rational functions + typedef CGAL::Algebraic_kernel_d_1 AK1; + typedef CGAL::Arr_rational_function_traits_2 Rational_traits; + typedef Dcel Rational_dcel; + typedef CGAL::Arrangement_with_history_2 + Rational_arr; +#endif +}; +} -//point location -typedef CGAL::Arr_trapezoid_ric_point_location - Arc_trap_point_location; -typedef CGAL::Arr_simple_point_location - Arc_simple_point_location; -typedef CGAL::Arr_walk_along_line_point_location - Arc_walk_point_location; -#if 0 // not supported -typedef CGAL::Arr_landmarks_point_location - Arc_landmarks_point_location; +#ifdef CGAL_USE_CORE + #define ARRANGEMENT_DEMO_SPECIALIZE_ARR_CORE(class_name) \ + template class class_name; \ + template class class_name; \ + template class class_name; \ + template class class_name; + #define ARRANGEMENT_DEMO_SPECIALIZE_TRAITS_CORE(class_name) \ + template class class_name; \ + template class class_name; \ + template class class_name; \ + template class class_name; +#else + #define ARRANGEMENT_DEMO_SPECIALIZE_ARR_CORE(class_name) + #define ARRANGEMENT_DEMO_SPECIALIZE_TRAITS_CORE(class_name) #endif -template -class My_observer : public CGAL::Arr_observer -{ -public: +#define ARRANGEMENT_DEMO_SPECIALIZE_ARR(class_name) \ + template class class_name; \ + template class class_name; \ + template class class_name; \ + ARRANGEMENT_DEMO_SPECIALIZE_ARR_CORE(class_name) - typedef Arrangement_ Arrangement; - typedef CGAL::Arr_observer Arr_observer; - typedef typename Arrangement::Face_handle Face_handle; - - My_observer (Arrangement& arr) : Arr_observer (arr) {} - - virtual void after_split_face (Face_handle f , - Face_handle new_f , - bool /* is_hole */) - { - new_f ->set_color(f->color()); - } -}; - -//Q_DECLARE_METATYPE( Seg_arr ) -//Q_DECLARE_METATYPE( Pol_arr ) -//Q_DECLARE_METATYPE( Conic_arr ) -Q_DECLARE_METATYPE( CGAL::Object ) +#define ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(class_name) \ + template class class_name; \ + template class class_name; \ + template class class_name; \ + ARRANGEMENT_DEMO_SPECIALIZE_TRAITS_CORE(class_name) #endif // ARRANGEMENT_DEMO_TYPES_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h new file mode 100644 index 00000000000..af97be31ca0 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ArrangementTypesUtils.h @@ -0,0 +1,151 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_TYPE_UTILS +#define ARRANGEMENT_DEMO_TYPE_UTILS + + +#include "ForwardDeclarations.h" +#include + +namespace demo_types +{ + +// avoid including "ArrangementTypes.h" at all costs for better compilation +// speed +struct DemoTypes; + +enum class TraitsType : int +{ + SEGMENT_TRAITS, + POLYLINE_TRAITS, + LINEAR_TRAITS, +#ifdef CGAL_USE_CORE + CONIC_TRAITS, + ALGEBRAIC_TRAITS, + BEZIER_TRAITS, + RATIONAL_FUNCTION_TRAITS, +#endif + NONE, +}; + +template +struct TypeHolder +{ + using type = T; +}; + +namespace details +{ +template +struct EnumFromTraits +{ + static constexpr TraitsType value = TraitsType::NONE; +}; +template +struct EnumFromTraits> +{ + static constexpr TraitsType value = TraitsType::SEGMENT_TRAITS; +}; +template +struct EnumFromTraits> +{ + static constexpr TraitsType value = TraitsType::POLYLINE_TRAITS; +}; +template +struct EnumFromTraits> +{ + static constexpr TraitsType value = TraitsType::LINEAR_TRAITS; +}; +#ifdef CGAL_USE_CORE +template +struct EnumFromTraits< + CGAL::Arr_conic_traits_2> +{ + static constexpr TraitsType value = TraitsType::CONIC_TRAITS; +}; +template < + typename RatKernel_, typename AlgKernel_, typename NtTraits_, + typename BoundingTraits_> +struct EnumFromTraits> +{ + static constexpr TraitsType value = TraitsType::BEZIER_TRAITS; +}; +template +struct EnumFromTraits> +{ + static constexpr TraitsType value = TraitsType::ALGEBRAIC_TRAITS; +}; +template +struct EnumFromTraits< + CGAL::Arr_rational_function_traits_2> +{ + static constexpr TraitsType value = TraitsType::RATIONAL_FUNCTION_TRAITS; +}; +#endif // CGAL_USE_CORE +} + +template +static constexpr TraitsType enumFromArrType() +{ + return details::EnumFromTraits::value; +} + +template +static void visitArrangementType(TraitsType tt, Lambda&& lambda) +{ + switch (tt) + { + case TraitsType::SEGMENT_TRAITS: + lambda(TypeHolder{}); + break; + case TraitsType::POLYLINE_TRAITS: + lambda(TypeHolder{}); + break; + case TraitsType::LINEAR_TRAITS: + lambda(TypeHolder{}); + break; +#ifdef CGAL_USE_CORE + case TraitsType::CONIC_TRAITS: + lambda(TypeHolder{}); + break; + case TraitsType::ALGEBRAIC_TRAITS: + lambda(TypeHolder{}); + break; + case TraitsType::BEZIER_TRAITS: + lambda(TypeHolder{}); + break; + case TraitsType::RATIONAL_FUNCTION_TRAITS: + lambda(TypeHolder{}); + break; +#endif + default: + CGAL_error(); + } +} + +template +static void forEachArrangementType(Lambda&& lambda) +{ + lambda(TypeHolder{}); + lambda(TypeHolder{}); + lambda(TypeHolder{}); +#ifdef CGAL_USE_CORE + lambda(TypeHolder{}); + lambda(TypeHolder{}); + lambda(TypeHolder{}); + lambda(TypeHolder{}); +#endif +} +} + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Arrangement_on_surface_2.qrc b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Arrangement_on_surface_2.qrc new file mode 100644 index 00000000000..05cf9a3fc3e --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Arrangement_on_surface_2.qrc @@ -0,0 +1,37 @@ + + + resources/icons/fill.xpm + resources/icons/conic_line.xpm + resources/icons/zoomin.xpm + resources/icons/zoomout.xpm + resources/icons/zoomreset.xpm + resources/icons/yellow_icon.xpm + resources/icons/red_icon.xpm + resources/icons/green_icon.xpm + resources/icons/blue_icon.xpm + resources/icons/pink_icon.xpm + resources/icons/conic_circle.xpm + resources/icons/conic_ellipse.xpm + resources/icons/conic_5points.xpm + resources/icons/conic_segment.xpm + resources/icons/conic_3points.xpm + resources/icons/snapvertex.xpm + resources/icons/conic_ray.xpm + resources/icons/lower_env_xpm.xpm + resources/icons/upper_env_xpm.xpm + resources/icons/grid.xpm + resources/icons/snapgrid.xpm + resources/icons/split.xpm + resources/icons/merge.xpm + resources/icons/rayshoot_down.xpm + resources/icons/rayshoot_up.xpm + resources/icons/insert.xpm + resources/icons/hand.xpm + resources/icons/delete.xpm + resources/icons/pointlocation.xpm + resources/icons/equation.xpm + + + resources/about.html + + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CMakeLists.txt index 21a67c6a7a7..9d17f95361a 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CMakeLists.txt @@ -1,7 +1,10 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.15) -project( Arrangement_on_surface_2_Demo ) +project(Arrangement_on_surface_2_Demo) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) if(NOT POLICY CMP0070 AND POLICY CMP0053) # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. @@ -12,77 +15,127 @@ if(POLICY CMP0071) cmake_policy(SET CMP0071 NEW) endif() -find_package(CGAL COMPONENTS Core Qt5 ) +find_package(CGAL QUIET COMPONENTS Qt5 OPTIONAL_COMPONENTS Core) +find_package(Qt5 QUIET COMPONENTS Gui Widgets) -find_package( Qt5 QUIET COMPONENTS Gui Widgets) - -if ( CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND AND CGAL_Core_FOUND) +if (CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND) include(${CGAL_USE_FILE}) + add_compile_definitions(QT_NO_KEYWORDS) + include_directories( BEFORE ./ ) # Arrangement package includes add_definitions(-DQT_NO_KEYWORDS) + option(COMPILE_UTILS_INCREMENTALLY + "Compile files in Utils directory incrementally, or compile them all as a unit. \ + Incremental compilation will be better for development and consume less \ + memory while compiling but will take longer to compile." + OFF) - qt5_wrap_ui( arrangement_2_uis - ArrangementDemoWindow.ui - NewTabDialog.ui - OverlayDialog.ui - ArrangementDemoPropertiesDialog.ui - ) - qt5_wrap_cpp( CGAL_Qt5_MOC_FILES - ArrangementDemoWindow.h - ArrangementDemoTab.h - Callback.h -# NewTabDialog.h - OverlayDialog.h - ArrangementDemoPropertiesDialog.h - ColorItemEditor.h - DeleteCurveModeItemEditor.h - PropertyValueDelegate.h - #PropertyValueDelegate.cpp - ) - qt5_add_resources( CGAL_Qt5_RESOURCE_FILES - ArrangementDemoWindow.qrc - ) - add_executable( arrangement_2 - arrangement_2.cpp - ArrangementGraphicsItem.cpp - ArrangementDemoWindow.cpp - ArrangementDemoTab.cpp - ArrangementDemoGraphicsView.cpp - Callback.cpp - VerticalRayShootCallback.cpp - EnvelopeCallback.cpp - SplitEdgeCallback.cpp - FillFaceCallback.cpp - GraphicsViewSegmentInput.cpp - GraphicsViewCurveInput.cpp - Utils.cpp - NewTabDialog.cpp - OverlayDialog.cpp - ArrangementDemoPropertiesDialog.cpp - ColorItemEditor.cpp - PropertyValueDelegate.cpp - DeleteCurveMode.cpp - DeleteCurveModeItemEditor.cpp - PointsGraphicsItem.cpp - VerticalRayGraphicsItem.cpp - ${CGAL_Qt5_MOC_FILES} - ${arrangement_2_uis} - ${CGAL_Qt5_RESOURCE_FILES} - ) - target_link_libraries( arrangement_2 PRIVATE - CGAL::CGAL CGAL::CGAL_Qt5 CGAL::CGAL_Core - Qt5::Gui + set(UTILS_SOURCE_FILES + "Utils/Utils.cpp" + "Utils/PointLocationFunctions.cpp" + "Utils/ConstructBoundingBox.cpp" + "Utils/EnvelopeFunctions.cpp" + "Utils/ConstructSegment.cpp" + "Utils/IntersectCurves.cpp" + "Utils/SplitAndMerge.cpp" ) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS arrangement_2 ) + if (COMPILE_UTILS_INCREMENTALLY) + set(UTILS_COMPILE_FILES ${UTILS_SOURCE_FILES}) + else() + set(UTILS_CPP_FILES_INCLUDES "") + foreach(utils_src IN LISTS UTILS_SOURCE_FILES) + string(APPEND UTILS_CPP_FILES_INCLUDES "#include \"${utils_src}\"\n") + endforeach() + file(WRITE "${CMAKE_BINARY_DIR}/CombinedUtils.cpp" ${UTILS_CPP_FILES_INCLUDES}) + set(UTILS_COMPILE_FILES "${CMAKE_BINARY_DIR}/CombinedUtils.cpp") + endif() + + + qt5_wrap_ui(arrangement_2_uis + ArrangementDemoWindow.ui + NewTabDialog.ui + OverlayDialog.ui + ArrangementDemoPropertiesDialog.ui + AlgebraicCurveInputDialog.ui + RationalCurveInputDialog.ui) + + qt5_wrap_cpp(CGAL_Qt5_MOC_FILES + ArrangementDemoWindow.h + ArrangementDemoTab.h + GraphicsViewCurveInput.h + Callback.h + OverlayDialog.h + ArrangementDemoPropertiesDialog.h + AlgebraicCurveInputDialog.h + RationalCurveInputDialog.h + ColorItemEditor.h + PropertyValueDelegate.h) + + qt5_add_resources(CGAL_Qt5_RESOURCE_FILES Arrangement_on_surface_2.qrc) + + add_executable(arrangement_2 + arrangement_2.cpp + ArrangementDemoWindow.cpp + ArrangementDemoTab.cpp + ArrangementDemoGraphicsView.cpp + ArrangementGraphicsItem.cpp + Callback.cpp + VerticalRayShootCallback.cpp + EnvelopeCallback.cpp + SplitEdgeCallback.cpp + FillFaceCallback.cpp + MergeEdgeCallback.cpp + PointLocationCallback.cpp + NewTabDialog.cpp + OverlayDialog.cpp + ArrangementDemoPropertiesDialog.cpp + AlgebraicCurveInputDialog.cpp + RationalCurveInputDialog.cpp + ColorItemEditor.cpp + PropertyValueDelegate.cpp + PointsGraphicsItem.cpp + VerticalRayGraphicsItem.cpp + DeleteCurveCallback.cpp + CurveGraphicsItem.cpp + ArrangementPainterOstream.cpp + GraphicsViewCurveInput.cpp + AlgebraicCurveParser.cpp + GraphicsSceneMixin.cpp + GridGraphicsItem.cpp + PointSnapper.cpp + CurveInputMethods.cpp + FloodFill.cpp + ArrangementIO.cpp + ${UTILS_COMPILE_FILES} + ${arrangement_2_uis} + ${CGAL_Qt5_RESOURCE_FILES} + ${CGAL_Qt5_MOC_FILES}) + + target_link_libraries(arrangement_2 Qt5::Core Qt5::Gui Qt5::Widgets) + target_link_libraries(arrangement_2 CGAL::CGAL CGAL::CGAL_Qt5) + if(CGAL_Core_FOUND) + target_link_libraries(arrangement_2 CGAL::CGAL_Core) + endif() + + add_to_cached_list(CGAL_EXECUTABLE_TARGETS arrangement_2) include(${CGAL_MODULES_DIR}/CGAL_add_test.cmake) cgal_add_compilation_test(arrangement_2) + else() + set(MISSING_DEPS "") - message(STATUS "NOTICE: This demo requires CGAL, CGAL-Core and Qt5, and will not be compiled.") - + if(NOT CGAL_FOUND) + set(MISSING_DEPS "CGAL, ${MISSING_DEPS}") + endif() + if(NOT CGAL_Qt5_FOUND) + set(MISSING_DEPS "the CGAL Qt5 library, ${MISSING_DEPS}") + endif() + if(NOT Qt5_FOUND) + set(MISSING_DEPS "Qt5, ${MISSING_DEPS}") + endif() + message(STATUS + "NOTICE: This demo requires ${MISSING_DEPS} and will not be compiled.") endif() - -# add_subdirectory( tests ) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.cpp index f882d0cfb8f..91308da672c 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "Callback.h" @@ -20,7 +21,8 @@ namespace CGAL { namespace Qt { -Callback::Callback( QObject* parent ) : QObject( parent ) { } +Callback::Callback(QObject* parent, QGraphicsScene* scene_) : + QObject(parent), GraphicsSceneMixin(scene_) { } void Callback::reset( ) { } @@ -31,23 +33,27 @@ bool Callback::eventFilter( QObject* object, QEvent* event ) QGraphicsSceneMouseEvent* mouseEvent = static_cast< QGraphicsSceneMouseEvent* >( event ); this->mouseMoveEvent( mouseEvent ); + return true; } else if ( event->type( ) == QEvent::GraphicsSceneMousePress ) { QGraphicsSceneMouseEvent* mouseEvent = static_cast< QGraphicsSceneMouseEvent* >( event ); this->mousePressEvent( mouseEvent ); + return true; } else if ( event->type( ) == QEvent::GraphicsSceneMouseRelease ) { QGraphicsSceneMouseEvent* mouseEvent = static_cast< QGraphicsSceneMouseEvent* >( event ); this->mouseReleaseEvent( mouseEvent ); + return true; } else if ( event->type( ) == QEvent::KeyPress ) { QKeyEvent* keyEvent = static_cast< QKeyEvent* >( event ); this->keyPressEvent( keyEvent ); + return true; } return QObject::eventFilter( object, event ); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.h index de21312f5e1..1674686ec9a 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Callback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,16 +7,15 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef CGAL_QT_CALLBACK_H #define CGAL_QT_CALLBACK_H #include +#include "GraphicsSceneMixin.h" -#include "Utils.h" - -class QRectF; class QEvent; class QKeyEvent; class QGraphicsScene; @@ -25,13 +24,14 @@ class QGraphicsSceneMouseEvent; namespace CGAL { namespace Qt { -class Callback : public QObject, public QGraphicsSceneMixin +class Callback : public QObject, public GraphicsSceneMixin { Q_OBJECT public: - Callback( QObject* parent ); + Callback( QObject* parent, QGraphicsScene* scene_ = nullptr ); virtual void reset( ); + virtual bool eventFilter( QObject* object, QEvent* event ); public Q_SLOTS: virtual void slotModelChanged( ); @@ -40,7 +40,6 @@ Q_SIGNALS: void modelChanged( ); protected: - virtual bool eventFilter( QObject* object, QEvent* event ); virtual void mousePressEvent( QGraphicsSceneMouseEvent* event ); virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event ); virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent* event ); @@ -49,4 +48,5 @@ protected: } // namespace Qt } // namespace CGAL + #endif // CGAL_QT_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ColorItemEditor.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ColorItemEditor.cpp index 69dba23a7f9..2de4a0d6e28 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ColorItemEditor.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ColorItemEditor.cpp @@ -48,21 +48,37 @@ #include "ColorItemEditor.h" +//! a pick color option +/*! + \param widget A QWidget pointer + \return a starting point to ask the user for color +*/ ColorItemEditor::ColorItemEditor( QWidget* widget ) : QPushButton( widget ) { this->setText( tr("Select a color") ); } +//! get the color reference +/*! + \return the Qcolor object of the selected color +*/ QColor ColorItemEditor::color( ) const { return this->m_color; } +//! a pick color option +/*! + \param color A QColor that the user selected to be changed +*/ void ColorItemEditor::setColor( QColor color ) { this->m_color = color; } +//! checking if the color reference that user wanted is valid or not +/*! +*/ void ColorItemEditor::mousePressEvent(QMouseEvent* /* e */) { QColor selectedColor = QColorDialog::getColor(this->m_color); diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h index 9537c3806ce..ada4f896c4d 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Conic_reader.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,15 +7,14 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef CGAL_CONIC_READER_H #define CGAL_CONIC_READER_H #include #include -#include -#include #include template @@ -33,16 +32,15 @@ public: typedef typename Traits::Rat_circle_2 Rat_circle_2; template - int read_data(const char * filename, OutputIterator curves_out, + int read_data(std::ifstream & inp, OutputIterator curves_out, CGAL::Bbox_2 & bbox) { Curve_2 cv; char dummy[256]; - std::ifstream inp(filename); if (!inp.is_open()) { - std::cerr << "Cannot open file " << filename << "!" << std::endl; + std::cerr << "Input stream is not open!" << std::endl; return -1; } int count; @@ -56,7 +54,6 @@ public: else bbox = bbox + curve_bbox; } } - inp.close(); return 0; } @@ -234,6 +231,54 @@ public: if (one_line[0] != '#') break; } } + + // should probably change class name since it reads and writes + template + int write_data(std::ofstream & ofs, InputIterator begin_, InputIterator end_) + { + ofs << std::distance(begin_, end_) << std::endl; + for (auto it = begin_; it != end_; ++it) + { + if (it->is_full_conic()) + { + ofs << "F "; + ofs << it->r() << " "; + ofs << it->s() << " "; + ofs << it->t() << " "; + ofs << it->u() << " "; + ofs << it->v() << " "; + ofs << it->w() << " "; + ofs << std::endl; + } + else if (it->orientation() == CGAL::COLLINEAR) + { + ofs << "S "; + ofs << it->source() << " "; + ofs << it->target() << " "; + ofs << std::endl; + } + else + { + ofs << "A "; + ofs << it->r() << " "; + ofs << it->s() << " "; + ofs << it->t() << " "; + ofs << it->u() << " "; + ofs << it->v() << " "; + ofs << it->w() << " "; + if (it->orientation() == CGAL::COUNTERCLOCKWISE) + ofs << "1 "; + else if (it->orientation() == CGAL::CLOCKWISE) + ofs << "-1 "; + else + ofs << "0 "; + ofs << it->source() << " "; + ofs << it->target() << " "; + ofs << std::endl; + } + } + return 0; + } }; #endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp new file mode 100644 index 00000000000..863f7945cbd --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.cpp @@ -0,0 +1,165 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include "CurveGraphicsItem.h" +#include "ArrangementPainterOstream.h" +#include "ArrangementTypes.h" +#include "Utils/ConstructBoundingBox.h" +#include "Utils/Utils.h" + +#include + +namespace CGAL +{ +namespace Qt +{ + +template +CurveGraphicsItem::CurveGraphicsItem() : + bb(), m_edgeColor(::Qt::red), m_edgeWidth(2), + m_vertexColor(::Qt::red), m_vertexRadius(1) +{ + this->setZValue(4); + this->pointsGraphicsItem.setParentItem(this); +} + +template +void CurveGraphicsItem::paint( + QPainter* painter, const QStyleOptionGraphicsItem* /* option */, + QWidget* /* widget */) +{ + // draw the curves + QPen edgesPen(this->m_edgeColor, this->m_edgeWidth); + edgesPen.setCosmetic(true); + painter->setPen(edgesPen); + + auto painterOstream = ArrangementPainterOstream(painter); + painterOstream.setScene(this->getScene()); + + for (auto& curve : this->curves) { painterOstream << curve; } +} + +template +QRectF CurveGraphicsItem::boundingRect() const +{ + auto viewport = this->viewportRect(); + qreal xmin = viewport.left(); + qreal ymin = viewport.top(); + qreal xmax = viewport.right(); + qreal ymax = viewport.bottom(); + if (this->bb.xmin() > xmin) xmin = this->bb.xmin(); + if (this->bb.ymin() > ymin) ymin = this->bb.ymin(); + if (this->bb.xmax() < xmax) xmax = this->bb.xmax(); + if (this->bb.ymax() < ymax) ymax = this->bb.ymax(); + if (xmin > xmax || ymin > ymax) + { + xmin = 0; + xmax = 0; + ymin = 0; + ymax = 0; + } + return {QPointF{xmin, ymin}, QPointF{xmax, ymax}}; +} + +template +void CurveGraphicsItem::insert(const X_monotone_curve_2& curve) +{ + this->curves.push_back(curve); + this->updateBoundingBox(); +} + +template +void CurveGraphicsItem::insert(const Point_2& point) +{ + this->pointsGraphicsItem.insert(point); + this->updateBoundingBox(); +} + +template +void CurveGraphicsItem::clear() +{ + this->curves.clear(); + this->pointsGraphicsItem.clear(); + + this->updateBoundingBox(); +} + +template +void CurveGraphicsItem::modelChanged() +{ + this->updateBoundingBox(); + this->update(); +} + +template +const QColor& CurveGraphicsItem::edgeColor() const +{ + return this->m_edgeColor; +} + +template +void CurveGraphicsItem::setEdgeColor(const QColor& color) +{ + this->m_edgeColor = color; +} + +template +int CurveGraphicsItem::edgeWidth() const +{ + return this->m_edgeWidth; +} + +template +void CurveGraphicsItem::setEdgeWidth(int width) +{ + this->m_edgeWidth = width; +} + +template +const QColor& CurveGraphicsItem::vertexColor() const +{ + return this->m_vertexColor; +} + +template +void CurveGraphicsItem::setVertexColor(const QColor& color) +{ + this->m_vertexColor = color; +} + +template +int CurveGraphicsItem::vertexRadius() const +{ + return this->m_vertexRadius; +} + +template +void CurveGraphicsItem::setVertexRadius(int radius) +{ + this->m_vertexRadius = radius; +} + +template +void CurveGraphicsItem::updateBoundingBox() +{ + this->prepareGeometryChange(); + + this->bb = {}; + ConstructBoundingBox construct_bounding_box; + for (auto& curve : curves) + this->bb += construct_bounding_box(curve); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(CurveGraphicsItem) + +} // namespace Qt +} // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h index 8e272884ff8..ce0fd6414f7 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveGraphicsItem.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,13 +7,14 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef CGAL_QT_CURVE_GRAPHICS_ITEM_H #define CGAL_QT_CURVE_GRAPHICS_ITEM_H -#include "ArrangementPainterOstream.h" -#include "Utils.h" +#include "PointsGraphicsItem.h" +#include "GraphicsSceneMixin.h" #include #include @@ -25,408 +26,47 @@ namespace Qt { /** Draws selected curves and vertices of an arrangement. */ +// TODO: ArrangementGraphicsItem should probably use this class template < class ArrTraits > -class CurveGraphicsItem : public GraphicsItem, public QGraphicsSceneMixin +class CurveGraphicsItem : public GraphicsItem, public GraphicsSceneMixin { public: // known curve types typedef ArrTraits Traits; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; typedef typename Traits::Curve_2 Curve_2; typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Point_2 Kernel_point_2; public: // ctors - CurveGraphicsItem( ): - painterOstream( 0 ), - boundingBox( 0, 0, 0, 0 ), - boundingBoxInitialized( false ), - m_edgeColor( ::Qt::red ), - m_edgeWidth( 0 ), - m_vertexColor( ::Qt::red ), - m_vertexRadius( 3 ) - { - this->setZValue( 4 ); - } + CurveGraphicsItem( ); public: // methods - virtual void paint(QPainter* painter, - const QStyleOptionGraphicsItem* /* option */, - QWidget* /* widget */) - { - // draw the curves - QPen edgesPen( this->m_edgeColor, this->m_edgeWidth ); - painter->setPen( edgesPen ); - QRectF clippingRectangle = this->viewportRect( ); - this->painterOstream = - ArrangementPainterOstream< Traits >( painter, clippingRectangle ); - this->painterOstream.setScene( this->getScene( ) ); - for ( unsigned int i = 0; i < this->curves.size( ); ++i ) - { - X_monotone_curve_2 curve = this->curves[ i ]; - this->painterOstream << curve; - } - - // draw the points - QPen verticesPen( this->m_vertexColor, this->m_vertexRadius ); - painter->setPen( verticesPen ); - for ( unsigned int i = 0; i < this->points.size( ); ++i ) - { - Point_2 arrPoint = this->points[ i ]; - Kernel_point_2 point( CGAL::to_double( arrPoint.x( ) ), - CGAL::to_double( arrPoint.y( ) ) ); - this->painterOstream << point; - } - } - - virtual QRectF boundingRect( ) const - { - QRectF boundingRectangle = this->convert( this->boundingBox ); - return boundingRectangle; - } - - void insert( const X_monotone_curve_2& curve ) - { - this->curves.push_back( curve ); - - this->updateBoundingBox( ); - } - - void insert( const Point_2& point ) - { - this->points.push_back( point ); - - this->updateBoundingBox( ); - } - - void clear( ) - { - this->curves.clear( ); - this->points.clear( ); - - this->updateBoundingBox( ); - } + void paint( + QPainter* painter, const QStyleOptionGraphicsItem* /* option */, + QWidget* /* widget */) override; + QRectF boundingRect( ) const override; + void insert( const X_monotone_curve_2& curve ); + void insert( const Point_2& point ); + void clear( ); public Q_SLOTS: - void modelChanged( ) - { - if ( this->curves.size( ) == 0 ) - { - this->hide( ); - } - else - { - this->show( ); - } - this->updateBoundingBox( ); - this->update( ); - } - - const QColor& edgeColor( ) const - { - return this->m_edgeColor; - } - - void setEdgeColor( const QColor& color ) - { - this->m_edgeColor = color; - } - - int edgeWidth( ) const - { - return this->m_edgeWidth; - } - - void setEdgeWidth( int width ) - { - this->m_edgeWidth = width; - } - - const QColor& vertexColor( ) const - { - return this->m_vertexColor; - } - - void setVertexColor( const QColor& color ) - { - this->m_vertexColor = color; - } - - int vertexRadius( ) const - { - return this->m_vertexRadius; - } - - void setVertexRadius( int radius ) - { - this->m_vertexRadius = radius; - } + void modelChanged( ) override; + const QColor& edgeColor( ) const; + void setEdgeColor( const QColor& color ); + int edgeWidth( ) const; + void setEdgeWidth( int width ); + const QColor& vertexColor( ) const; + void setVertexColor( const QColor& color ); + int vertexRadius( ) const; + void setVertexRadius( int radius ); protected: // methods - void updateBoundingBox( ) - { - this->prepareGeometryChange( ); - - if ( this->curves.size( ) == 0 ) - { - this->boundingBox = Bbox_2( 0, 0, 0, 0 ); - this->boundingBoxInitialized = false; - return; - } - - this->boundingBox = this->curves[ 0 ].bbox( ); - this->boundingBoxInitialized = true; - for ( unsigned int i = 1; i < this->curves.size( ); ++i ) - { - this->boundingBox = this->boundingBox + this->curves[ i ].bbox( ); - } - - for ( unsigned int i = 0; i < this->points.size( ); ++i ) - { - Point_2 pt = this->points[ i ]; - Kernel_point_2 point(CGAL::to_double(pt.x()), CGAL::to_double(pt.y())); - this->boundingBox = this->boundingBox + point.bbox( ); - } - } + void updateBoundingBox( ); protected: // fields - CGAL::Qt::Converter< Kernel > convert; - ArrangementPainterOstream< Traits > painterOstream; std::vector< X_monotone_curve_2 > curves; - std::vector< Point_2 > points; - CGAL::Bbox_2 boundingBox; - bool boundingBoxInitialized; - - QColor m_edgeColor; - int m_edgeWidth; - QColor m_vertexColor; - int m_vertexRadius; - -}; // class CurveGraphicsItem - -/** - Specialization of the base template CurveGraphicsItem: - - updateBoundingBox -*/ -template < class Kernel_ > -class CurveGraphicsItem< CGAL::Arr_linear_traits_2< Kernel_ > > : - public GraphicsItem, public QGraphicsSceneMixin -{ -public: // typedefs - // known curve types - typedef CGAL::Arr_linear_traits_2< Kernel_ > Traits; - typedef Kernel_ Kernel; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Line_2 Line_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Kernel::Point_2 Kernel_point_2; - -public: // ctors - CurveGraphicsItem( ): - painterOstream( 0 ), - boundingBox( 0, 0, 0, 0 ), - boundingBoxInitialized( false ) - { - this->setZValue( 4 ); - } - -public: // methods - virtual void paint(QPainter* painter, - const QStyleOptionGraphicsItem* /* option */, - QWidget* /* widget */) - { - QRectF clippingRectangle = this->viewportRect( ); - painter->setPen( QPen( ::Qt::red, 0. ) ); - this->painterOstream = - ArrangementPainterOstream< Traits >( painter, clippingRectangle ); - for ( unsigned int i = 0; i < this->curves.size( ); ++i ) - { - X_monotone_curve_2 curve = this->curves[ i ]; - this->painterOstream << curve; - } - for ( unsigned int i = 0; i < this->points.size( ); ++i ) - { - Point_2 arrPoint = this->points[ i ]; - Kernel_point_2 point( CGAL::to_double( arrPoint.x( ) ), - CGAL::to_double( arrPoint.y( ) ) ); - this->painterOstream << point; - } - } - - void insert( const X_monotone_curve_2& curve ) - { - this->curves.push_back( curve ); - this->updateBoundingBox( ); - } - - void insert( const Point_2& point ) - { - this->points.push_back( point ); - } - - void clear( ) - { - this->curves.clear( ); - this->points.clear( ); - } - - QRectF boundingRect( ) const - { - QRectF res; - if ( this->getScene( ) == NULL ) - { - return res; - } - return this->convert( this->boundingBox ); - } - - virtual void setScene( QGraphicsScene* scene_ ) - { - this->QGraphicsSceneMixin::setScene( scene_ ); - if ( this->getScene( ) == NULL ) - { - QRectF clipRect = this->viewportRect( ); - this->convert = CGAL::Qt::Converter< Kernel >( clipRect ); - } - } - -public Q_SLOTS: - void modelChanged( ) - { - if ( this->curves.size( ) == 0 ) - { - this->hide( ); - } - else - { - this->show( ); - } - this->updateBoundingBox( ); - this->update( ); - } - - const QColor& edgeColor( ) const - { - return this->m_edgeColor; - } - - void setEdgeColor( const QColor& color ) - { - this->m_edgeColor = color; - } - - int edgeWidth( ) const - { - return this->m_edgeWidth; - } - - void setEdgeWidth( int width ) - { - this->m_edgeWidth = width; - } - - const QColor& vertexColor( ) const - { - return this->m_vertexColor; - } - - void setVertexColor( const QColor& color ) - { - this->m_vertexColor = color; - } - - int vertexRadius( ) const - { - return this->m_vertexRadius; - } - - void setVertexRadius( int radius ) - { - this->m_vertexRadius = radius; - } - -protected: // methods - void updateBoundingBox( ) - { - this->boundingBoxInitialized = 0; - this->boundingBox = CGAL::Bbox_2( 0, 0, 0, 0 ); - QRectF clipRect = this->viewportRect( ); - if ( !clipRect.isValid( ) ) - { - return; - } - this->convert = CGAL::Qt::Converter< Kernel >( clipRect ); - - bool first = 1; - for ( unsigned int i = 0; i < curves.size( ); ++i ) - { - X_monotone_curve_2 curve = curves[ i ]; - if ( curve.is_segment( ) ) - { - Segment_2 seg = curve.segment( ); - CGAL::Bbox_2 seg_bbox = seg.bbox( ); - if ( first ) - { - first = 0; - this->boundingBoxInitialized = 1; - this->boundingBox = seg_bbox; - } - else - { - this->boundingBox = this->boundingBox + seg_bbox; - } - } - else if ( curve.is_ray( ) ) - { - Ray_2 ray = curve.ray( ); - QLineF qclippedRay = this->convert( ray ); - if ( qclippedRay.isNull( ) ) - continue; - Segment_2 clippedRay = this->convert( qclippedRay ); - if ( first ) - { - first = 0; - this->boundingBoxInitialized = 1; - this->boundingBox = clippedRay.bbox( ); - } - else - { - this->boundingBox = this->boundingBox + clippedRay.bbox( ); - } - } - else // curve.is_line( ) - { - Line_2 line = curve.line( ); - QLineF qclippedLine = this->convert( line ); - if ( qclippedLine.isNull( ) ) - continue; - Segment_2 clippedLine = this->convert( qclippedLine ); - if ( first ) - { - first = 0; - this->boundingBoxInitialized = 1; - this->boundingBox = clippedLine.bbox( ); - } - else - { - this->boundingBox = this->boundingBox + clippedLine.bbox( ); - } - } - } - } - -protected: // fields - CGAL::Qt::Converter< Kernel > convert; - ArrangementPainterOstream< Traits > painterOstream; - std::vector< X_monotone_curve_2 > curves; - std::vector< Point_2 > points; - CGAL::Bbox_2 boundingBox; - bool boundingBoxInitialized; + PointsGraphicsItem pointsGraphicsItem; + CGAL::Bbox_2 bb; QColor m_edgeColor; int m_edgeWidth; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.cpp new file mode 100644 index 00000000000..91a64dad22e --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.cpp @@ -0,0 +1,449 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "CurveInputMethods.h" +#include +#include +#include +#include +#include + +namespace CGAL +{ +namespace Qt +{ + +CurveInputMethod::CurveInputMethod(CurveType type_, int numPoints_) : + Callback(nullptr), numPoints{numPoints_}, callback{nullptr}, type{type_}, + itemsAdded{false} +{ + if (numPoints > 0) clickedPoints.reserve(numPoints); + this->pointsGraphicsItem.setZValue(100); +} + +void CurveInputMethod::setColor(QColor c) +{ + this->color = c; + this->pointsGraphicsItem.setColor(c); +} + +QColor CurveInputMethod::getColor() const +{ + return this->color; +} + +void CurveInputMethod::setCallback(CurveInputMethodCallback* callback_) +{ + this->callback = callback_; +} + +void CurveInputMethod::setPointSnapper(PointSnapperBase* snapper_) +{ + this->snapper = snapper_; +} + +CurveType CurveInputMethod::curveType() const { return type; } + + +void CurveInputMethod::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + if (this->clickedPoints.size() > 0) + this->updateVisualGuideMouseMoved( + this->clickedPoints, this->snapQPoint(event)); +} + +void CurveInputMethod::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + if (event->button() == ::Qt::LeftButton) + { + Point_2 big_point = this->snapPoint(event); + QPointF point = { + CGAL::to_double(big_point.x()), CGAL::to_double(big_point.y())}; + + // only accept unique consecutive points + if (!this->clickedPoints.empty() && this->clickedPoints.back() == point) + return; + this->clickedPoints.push_back(point); + this->clickedBigPoints.push_back(big_point); + + if (this->clickedPoints.size() < static_cast(this->numPoints)) + { + if (this->clickedPoints.size() == 1) this->beginInput_(); + this->pointsGraphicsItem.insert(point); + this->updateVisualGuideNewPoint(this->clickedPoints); + } + else + { + if (this->callback) + callback->curveInputDoneEvent(this->clickedBigPoints, this->type); + this->reset(); + } + } + else if (event->button() == ::Qt::RightButton) + { + if (this->numPoints == -1 && this->callback) + callback->curveInputDoneEvent(this->clickedBigPoints, this->type); + this->reset(); + } +} + +void CurveInputMethod::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == ::Qt::Key_Escape) + this->reset(); +} + +void CurveInputMethod::beginInput_() +{ + this->beginInput(); + this->itemsAdded = true; + this->getScene()->addItem(&(this->pointsGraphicsItem)); + for (auto& item : items) this->getScene()->addItem(item); +} + +static inline void clearPainterPath(QPainterPath& ppath) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) + ppath.clear(); +#else + ppath = {}; +#endif +} + +void CurveInputMethod::reset() +{ + this->resetInput(); + this->clickedPoints.clear(); + this->clickedBigPoints.clear(); + this->pointsGraphicsItem.clear(); + if (this->itemsAdded) + { + this->getScene()->removeItem(&(this->pointsGraphicsItem)); + for (auto& item : items) this->getScene()->removeItem(item); + this->itemsAdded = false; + } +} + +void CurveInputMethod::resetInput() { } +void CurveInputMethod::beginInput() { } + +void CurveInputMethod::updateVisualGuideNewPoint(const std::vector&) { +} + +void CurveInputMethod::updateVisualGuideMouseMoved( + const std::vector&, const QPointF&) +{ +} + +auto CurveInputMethod::snapPoint(QGraphicsSceneMouseEvent* event) -> Point_2 +{ + return this->snapper->snapPoint(event->scenePos()); +} + +QPointF CurveInputMethod::snapQPoint(QGraphicsSceneMouseEvent* event) +{ + auto&& pt = this->snapPoint(event); + return QPointF{CGAL::to_double(pt.x()), CGAL::to_double(pt.y())}; +} + +void CurveInputMethod::appendGraphicsItem(QGraphicsItem* item) +{ + items.push_back(item); + item->setZValue(100); +} + +// SegmentInputMethod +SegmentInputMethod::SegmentInputMethod() : + CurveInputMethod(CurveType::Segment, 2) +{ + this->appendGraphicsItem(&(this->segmentGuide)); +} + +void SegmentInputMethod::beginInput() +{ + this->segmentGuide.setLine(0, 0, 0, 0); + QPen pen = this->segmentGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->segmentGuide.setPen(pen); +} + +void SegmentInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + QLineF segment{clickedPoints[0], movePoint}; + this->segmentGuide.setLine(segment); +} + +// PolylineInputMethod +PolylineInputMethod::PolylineInputMethod() : + CurveInputMethod(CurveType::Polyline, -1) +{ + this->appendGraphicsItem(&(this->polylineGuide)); + this->appendGraphicsItem(&(this->lastLine)); +} + +void PolylineInputMethod::beginInput() +{ + clearPainterPath(this->painterPath); + this->polylineGuide.setPath(this->painterPath); + this->lastLine.setLine(0, 0, 0, 0); + QPen pen = this->polylineGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->polylineGuide.setPen(pen); + this->lastLine.setPen(pen); +} + +void PolylineInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + this->lastLine.setLine(QLineF{clickedPoints.back(), movePoint}); +} + +void PolylineInputMethod::updateVisualGuideNewPoint( + const std::vector& points) +{ + if (points.size() == 1) + this->painterPath.moveTo(points.back()); + else + this->painterPath.lineTo(points.back()); + + this->polylineGuide.setPath(this->painterPath); +} + +// RayInputMethod +RayInputMethod::RayInputMethod() : CurveInputMethod(CurveType::Ray, 2) +{ + this->appendGraphicsItem(&(this->rayGuide)); +} + +void RayInputMethod::beginInput() +{ + this->rayGuide.setLine(0, 0, 0, 0); + QPen pen = this->rayGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->rayGuide.setPen(pen); +} + +void RayInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + float length = QLineF{clickedPoints[0], movePoint}.length(); + float dx = (movePoint.x() - clickedPoints[0].x()) / length; + float dy = (movePoint.y() - clickedPoints[0].y()) / length; + QRectF viewport = this->viewportRect(); + float r = std::sqrt( + viewport.width() * viewport.width() + + viewport.height() * viewport.height()); + QPointF endPoint = { + clickedPoints[0].x() + dx * r, clickedPoints[0].y() + dy * r}; + QLineF segment{clickedPoints[0], endPoint}; + this->rayGuide.setLine(segment); +} + +// LineInputMethod +LineInputMethod::LineInputMethod() : CurveInputMethod(CurveType::Line, 2) +{ + this->appendGraphicsItem(&(this->lineGuide)); +} + +void LineInputMethod::beginInput() +{ + this->lineGuide.setLine(0, 0, 0, 0); + QPen pen = this->lineGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->lineGuide.setPen(pen); +} + +void LineInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + if (clickedPoints[0] == movePoint) + { + this->lineGuide.setLine({}); + return; + } + float length = QLineF{clickedPoints[0], movePoint}.length(); + float dx = (clickedPoints[0].x() - movePoint.x()) / length; + float dy = (clickedPoints[0].y() - movePoint.y()) / length; + QRectF viewport = this->viewportRect(); + float r = std::sqrt( + viewport.width() * viewport.width() + + viewport.height() * viewport.height()); + QPointF endPoint = { + clickedPoints[0].x() + dx * r, clickedPoints[0].y() + dy * r}; + QPointF firstPoint = { + clickedPoints[0].x() - dx * r, clickedPoints[0].y() - dy * r}; + QLineF segment{firstPoint, endPoint}; + this->lineGuide.setLine(segment); +} + +// CircleInputMethod +CircleInputMethod::CircleInputMethod() : CurveInputMethod(CurveType::Circle, 2) +{ + this->appendGraphicsItem(&(this->circleGuide)); +} + +void CircleInputMethod::beginInput() +{ + this->circleGuide.setRect(0, 0, 0, 0); + QPen pen = this->circleGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->circleGuide.setPen(pen); +} + +void CircleInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + auto& center = clickedPoints.front(); + float radius = QLineF{center, movePoint}.length(); + this->circleGuide.setRect( + center.x() - radius, center.y() - radius, 2 * radius, 2 * radius); +} + +// EllipseInputMethod +EllipseInputMethod::EllipseInputMethod() : + CurveInputMethod(CurveType::Ellipse, 2) +{ + this->appendGraphicsItem(&(this->ellipseGuide)); +} + +void EllipseInputMethod::beginInput() +{ + this->ellipseGuide.setRect(0, 0, 0, 0); + QPen pen = this->ellipseGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->ellipseGuide.setPen(pen); +} + +void EllipseInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + this->ellipseGuide.setRect(QRectF{clickedPoints[0], movePoint}); +} + +// ThreePointCircularInputMethod +ThreePointCircularInputMethod::ThreePointCircularInputMethod() : + CurveInputMethod(CurveType::ThreePointCircularArc, 3) +{ +} + +// FivePointConicInputMethod +FivePointConicInputMethod::FivePointConicInputMethod() : + CurveInputMethod(CurveType::FivePointConicArc, 5) +{ +} + +// BezierInputMethod +BezierInputMethod::BezierInputMethod() : CurveInputMethod(CurveType::Bezier, -1) +{ + this->appendGraphicsItem(&(this->bezierGuide)); + this->appendGraphicsItem(&(this->bezierOldGuide)); +} + +void BezierInputMethod::beginInput() +{ + clearPainterPath(this->painterOldPath); + clearPainterPath(this->painterPath); + this->bezierGuide.setPath(this->painterPath); + this->bezierOldGuide.setPath(this->painterOldPath); + + QPen pen = this->bezierOldGuide.pen(); + pen.setColor(this->color); + pen.setCosmetic(true); + this->bezierOldGuide.setPen(pen); + + // TODO: set bezier guide color dynamically + pen = this->bezierGuide.pen(); + pen.setColor(::Qt::darkGray); + pen.setCosmetic(true); + this->bezierGuide.setPen(pen); +} + +static QPointF evalBezier( + const std::vector& control_points, std::vector& cache, + float t) +{ + // iterative de Casteljau Algorithm + cache.clear(); + + for (size_t j = 0; j + 1 < control_points.size(); j++) + cache.push_back(control_points[j] * (1.0f - t) + control_points[j + 1] * t); + + for (size_t i = 1; i + 1 < control_points.size(); i++) + for (size_t j = 0; j + i + 1 < control_points.size(); j++) + cache[j] = cache[j] * (1.0f - t) + cache[j + 1] * t; + + return cache[0]; +} + +static float approx_pixel_length( + const std::vector& control_points, const QTransform& worldTransform) +{ + float l = 0; + for (size_t i = 0; i + 1 < control_points.size(); i++) + { + QPointF p1 = worldTransform.map(control_points[i]); + QPointF p2 = worldTransform.map(control_points[i + 1]); + l += QLineF{p1, p2}.length(); + } + return l; +} + +static void updateBezierPainterPath( + const std::vector& controlPoints, std::vector& cache, + const QTransform& worldTransform, QPainterPath& painterPath) +{ + clearPainterPath(painterPath); + if (controlPoints.size() < 2) return; + + float pixel_len = approx_pixel_length(controlPoints, worldTransform); + static constexpr int PIXEL_DIV = 4; + int num_segs = (std::max)(1, static_cast(pixel_len / PIXEL_DIV)); + + painterPath.moveTo(controlPoints[0]); + for (int i = 0; i < num_segs; i++) + painterPath.lineTo( + evalBezier(controlPoints, cache, static_cast(i + 1) / num_segs)); +} + +void BezierInputMethod::updateVisualGuideMouseMoved( + const std::vector& clickedPoints, const QPointF& movePoint) +{ + this->controlPoints.clear(); + std::copy( + clickedPoints.begin(), clickedPoints.end(), + std::back_inserter(this->controlPoints)); + this->controlPoints.push_back(movePoint); + + updateBezierPainterPath( + this->controlPoints, this->cache, this->getView()->transform(), + this->painterPath); + + this->bezierGuide.setPath(this->painterPath); +} + +void BezierInputMethod::updateVisualGuideNewPoint( + const std::vector& clickedPoints) +{ + updateBezierPainterPath( + clickedPoints, this->cache, this->getView()->transform(), + this->painterOldPath); + this->bezierOldGuide.setPath(this->painterPath); +} + +} // namespace Qt +} // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.h new file mode 100644 index 00000000000..6cbd447c457 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/CurveInputMethods.h @@ -0,0 +1,229 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_CURVE_INPUT_METHODS_H +#define ARRANGEMENT_DEMO_CURVE_INPUT_METHODS_H + +#include +#include + +#include "Callback.h" +#include "PointSnapper.h" +#include "PointsGraphicsItem.h" + +class QEvent; +class QKeyEvent; +class QGraphicsSceneMouseEvent; + +namespace CGAL +{ + +namespace Qt +{ +enum class CurveType : int +{ + Segment, + Polyline, + Ray, + Line, + Circle, + Ellipse, + ThreePointCircularArc, + FivePointConicArc, + Bezier, + None, +}; + +class CurveInputMethodCallback +{ +public: + using Point_2 = PointSnapperBase::Point_2; + + virtual void curveInputDoneEvent( + const std::vector& clickedPoints, CurveType type) = 0; +}; + +class CurveInputMethod : public Callback +{ +public: + using Point_2 = PointSnapperBase::Point_2; + + CurveInputMethod(CurveType, int numPoints_ = -1); + virtual ~CurveInputMethod() { } + + void setCallback(CurveInputMethodCallback*); + void setPointSnapper(PointSnapperBase*); + CurveType curveType() const; + + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + void keyPressEvent(QKeyEvent* event) override; + void reset() override; + + void setColor(QColor); + QColor getColor() const; + + Point_2 snapPoint(QGraphicsSceneMouseEvent* event); + QPointF snapQPoint(QGraphicsSceneMouseEvent* event); + +protected: + void beginInput_(); + virtual void beginInput(); + virtual void resetInput(); + virtual void updateVisualGuideNewPoint(const std::vector&); + virtual void + updateVisualGuideMouseMoved(const std::vector&, const QPointF&); + void appendGraphicsItem(QGraphicsItem* item); + +protected: + QColor color; + +private: + const int numPoints; + std::vector clickedPoints; + std::vector clickedBigPoints; + PointsGraphicsItem pointsGraphicsItem; + CurveInputMethodCallback* callback; + const CurveType type; + std::vector items; + bool itemsAdded; + PointSnapperBase* snapper; +}; + +class SegmentInputMethod : public CurveInputMethod +{ +public: + SegmentInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsLineItem segmentGuide; +}; + +class RayInputMethod : public CurveInputMethod +{ +public: + RayInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsLineItem rayGuide; +}; + +class LineInputMethod : public CurveInputMethod +{ +public: + LineInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsLineItem lineGuide; +}; + +class PolylineInputMethod : public CurveInputMethod +{ +public: + PolylineInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + + void updateVisualGuideNewPoint(const std::vector&) override; + +private: + QGraphicsPathItem polylineGuide; + QGraphicsLineItem lastLine; + QPainterPath painterPath; +}; + +class CircleInputMethod : public CurveInputMethod +{ +public: + CircleInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsEllipseItem circleGuide; +}; + +class EllipseInputMethod : public CurveInputMethod +{ +public: + EllipseInputMethod(); + + void beginInput() override; + + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsEllipseItem ellipseGuide; +}; + +class ThreePointCircularInputMethod : public CurveInputMethod +{ +public: + ThreePointCircularInputMethod(); +}; + +class FivePointConicInputMethod : public CurveInputMethod +{ +public: + FivePointConicInputMethod(); +}; + +class BezierInputMethod : public CurveInputMethod +{ +public: + BezierInputMethod(); + void beginInput() override; + void updateVisualGuideNewPoint(const std::vector&) override; + void updateVisualGuideMouseMoved( + const std::vector& clickedPoints, + const QPointF& movePoint) override; + +private: + QGraphicsPathItem bezierOldGuide; + QGraphicsPathItem bezierGuide; + QPainterPath painterOldPath; + QPainterPath painterPath; + std::vector controlPoints; + std::vector cache; +}; + +} // namespace Qt +} // namespace CGAL + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp new file mode 100644 index 00000000000..d30c5493d14 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include +#include + +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveGraphicsItem.h" +#include "DeleteCurveCallback.h" +#include "Utils/Utils.h" + +template +class DeleteCurveCallback : public DeleteCurveCallbackBase +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Halfedge_handle Halfedge_handle; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Arrangement::Curve_handle Curve_handle; + typedef + typename Arrangement::Originating_curve_iterator Originating_curve_iterator; + typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; + + DeleteCurveCallback(Arrangement* arr_, QObject* parent_); + void setScene(QGraphicsScene* scene_) override; + void reset() override; + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + void highlightNearestCurve(QGraphicsSceneMouseEvent* event); + + CGAL::Qt::CurveGraphicsItem* highlightedCurve; + Arrangement* arr; + Halfedge_handle removableHalfedge; +}; // class DeleteCurveCallback + +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new DeleteCurveCallback(arr, parent); + } + + DeleteCurveCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +DeleteCurveCallbackBase* DeleteCurveCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + DeleteCurveCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +/*! Constructor */ +template +DeleteCurveCallback::DeleteCurveCallback( + Arrangement* arr_, QObject* parent_) : + DeleteCurveCallbackBase(parent_), + highlightedCurve(new CGAL::Qt::CurveGraphicsItem()), arr(arr_) +{ + QObject::connect( + this, SIGNAL(modelChanged()), this->highlightedCurve, SLOT(modelChanged())); + + this->setDeleteMode(DeleteMode::DeleteOriginatingCuve); +} + +//! Setter Function. +/*! + sets the current scene of the viewport +*/ +template +void DeleteCurveCallback::setScene(QGraphicsScene* scene_) +{ + CGAL::Qt::Callback::setScene(scene_); + this->highlightedCurve->setScene(scene_); + if (this->scene) { this->scene->addItem(this->highlightedCurve); } +} + +template +void DeleteCurveCallback::reset() +{ + this->highlightedCurve->clear(); + this->removableHalfedge = Halfedge_handle(); +} + +template +void DeleteCurveCallback::mousePressEvent( + QGraphicsSceneMouseEvent* /* event */) +{ + if (this->removableHalfedge == Halfedge_handle()) { return; } + + if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) + { + Originating_curve_iterator it = + this->arr->originating_curves_begin(this->removableHalfedge); + Originating_curve_iterator it_end = + this->arr->originating_curves_end(this->removableHalfedge); + while (it != it_end) + { + Originating_curve_iterator temp = it; + ++temp; + CGAL::remove_curve(*(this->arr), it); + it = temp; + } + } + else + { + // CGAL::remove_edge( *(this->arr), this->removableHalfedge->curve( ) ); + this->arr->remove_edge(this->removableHalfedge); + } + this->reset(); + Q_EMIT modelChanged(); +} + +template +void DeleteCurveCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + this->highlightNearestCurve(event); +} + +template +void DeleteCurveCallback::highlightNearestCurve( + QGraphicsSceneMouseEvent* event) +{ + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point; + + CGAL::Qt::Converter convert; + // find the nearest curve to the cursor to be the new highlighted curve + Point p = convert(event->scenePos()); + + Find_nearest_edge findNearestEdge(this->arr); + findNearestEdge.setScene(this->scene); + auto nearestEdge = findNearestEdge(p); + this->removableHalfedge = this->arr->non_const_handle(nearestEdge); + + // now 'removableHalfedge' holds the closest halfedge to the point of the + // mouse + // this->removableHalfedge = nearestHei; + // if ( isFirst ) + if (this->removableHalfedge == Halfedge_handle()) { return; } + + // create a curve graphics item and add it to the scene + this->highlightedCurve->clear(); + if (this->deleteMode == DeleteMode::DeleteOriginatingCuve) + { // highlight the originating curve + Originating_curve_iterator ocit, temp; + ocit = this->arr->originating_curves_begin(this->removableHalfedge); + while (ocit != this->arr->originating_curves_end(this->removableHalfedge)) + { + temp = ocit; + ++temp; + + Curve_handle ch = ocit; + Induced_edge_iterator itr; + for (itr = this->arr->induced_edges_begin(ch); + itr != this->arr->induced_edges_end(ch); ++itr) + { + auto curve = (*itr)->curve(); + this->highlightedCurve->insert(curve); + } + ocit = temp; + } + } + else + { // highlight just the edge + this->highlightedCurve->insert(this->removableHalfedge->curve()); + } + + Q_EMIT modelChanged(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.h index deb7a06bf70..c41e9aa51ec 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveCallback.h @@ -14,206 +14,35 @@ #include "Callback.h" -//#include -#include -#include +namespace demo_types +{ +enum class TraitsType : int; +} -#include -//#include - -#include "CurveGraphicsItem.h" -#include "Utils.h" +enum class DeleteMode +{ + DeleteOriginatingCuve, + DeleteEdge, +}; /** Handles deletion of arrangement curves selected from the scene. The template parameter is a CGAL::Arrangement_with_history_2 of some type. */ -template < typename Arr_ > -class DeleteCurveCallback : public CGAL::Qt::Callback +class DeleteCurveCallbackBase : public CGAL::Qt::Callback { public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Point; - typedef typename Kernel::Segment_2 Segment; + static DeleteCurveCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); - DeleteCurveCallback( Arrangement* arr_, QObject* parent_ ); - void setScene( QGraphicsScene* scene_ ); - QGraphicsScene* getScene( ) const; - void reset( ); + void setDeleteMode(DeleteMode deleteMode_) { this->deleteMode = deleteMode_; } + DeleteMode getDeleteMode() { return this->deleteMode; } protected: - void mousePressEvent( QGraphicsSceneMouseEvent *event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent *event ); - void highlightNearestCurve( QGraphicsSceneMouseEvent *event ); + using CGAL::Qt::Callback::Callback; - Compute_squared_distance_2< Traits > squaredDistance; - CGAL::Qt::Converter< Kernel > convert; - QGraphicsScene* scene; - CGAL::Qt::CurveGraphicsItem< Traits >* highlightedCurve; - Arrangement* arr; - Halfedge_handle removableHalfedge; -}; // class DeleteCurveCallback - -/*! Constructor */ -template < typename Arr_ > -DeleteCurveCallback< Arr_ >:: -DeleteCurveCallback( Arrangement* arr_, QObject* parent_ ) : - CGAL::Qt::Callback( parent_ ), - scene( NULL ), - highlightedCurve( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ), - arr( arr_ ) -{ - QObject::connect( this, SIGNAL( modelChanged( ) ), - this->highlightedCurve, SLOT( modelChanged( ) ) ); -} - -template < typename Arr_ > -void DeleteCurveCallback< Arr_ >::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; - this->highlightedCurve->setScene( scene_ ); - if ( this->scene ) - { - this->scene->addItem( this->highlightedCurve ); - } -} - -template < typename Arr_ > -QGraphicsScene* DeleteCurveCallback< Arr_ >::getScene( ) const -{ - return this->scene; -} - -template < typename Arr_ > -void DeleteCurveCallback< Arr_ >::reset( ) -{ - this->highlightedCurve->clear( ); - this->removableHalfedge = Halfedge_handle( ); - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void -DeleteCurveCallback::mousePressEvent(QGraphicsSceneMouseEvent* /* event */) -{ - if ( this->removableHalfedge == Halfedge_handle( ) ) - { - return; - } - - bool deleteOriginatingCurve = 1; - if ( deleteOriginatingCurve ) - { - Originating_curve_iterator it = - this->arr->originating_curves_begin( this->removableHalfedge ); - Originating_curve_iterator it_end = - this->arr->originating_curves_end( this->removableHalfedge ); - while ( it != it_end ) - { - Originating_curve_iterator temp = it; - ++temp; - CGAL::remove_curve( *(this->arr), it ); - it = temp; - } - } - else - { - //CGAL::remove_edge( *(this->arr), this->removableHalfedge->curve( ) ); - this->arr->remove_edge( this->removableHalfedge ); - } - - this->reset( ); -} - -template < typename Arr_ > -void DeleteCurveCallback< Arr_ >:: -mouseMoveEvent( QGraphicsSceneMouseEvent* event ) -{ - this->highlightNearestCurve( event ); -} - -template < typename Arr_ > -void -DeleteCurveCallback< Arr_ >:: -highlightNearestCurve( QGraphicsSceneMouseEvent* event ) -{ - // find the nearest curve to the cursor to be the new highlighted curve - Point p = this->convert( event->scenePos( ) ); - //bool isFirst = true; - //double minDist = 0.0; - //Halfedge_iterator nearestHei; - -#if 0 - for ( Halfedge_iterator hei = this->arr->halfedges_begin( ); - hei != this->arr->halfedges_end( ); - ++hei ) - { - X_monotone_curve_2 curve = hei->curve( ); - double dist = CGAL::to_double( this->squaredDistance( p, curve ) ); - // std::cout << dist << std::endl; - if ( isFirst || dist < minDist ) - { - isFirst = false; - minDist = dist; - nearestHei = hei; - } - } -#endif - Find_nearest_edge< Arr_ > findNearestEdge( this->arr ); - findNearestEdge.setScene( this->scene ); - Halfedge_const_handle nearestEdge = findNearestEdge( p ); - this->removableHalfedge = this->arr->non_const_handle( nearestEdge ); - - // now 'removableHalfedge' holds the closest halfedge to the point of the mouse - //this->removableHalfedge = nearestHei; - //if ( isFirst ) - if ( this->removableHalfedge == Halfedge_handle( ) ) - { - // std::cout << "no curve found" << std::endl; - return; - } - - // create a curve graphics item and add it to the scene - bool deleteOriginatingCurve = 1; - this->highlightedCurve->clear( ); - if ( deleteOriginatingCurve ) - { // highlight the originating curve - Originating_curve_iterator ocit, temp; - ocit = this->arr->originating_curves_begin( this->removableHalfedge ); - while (ocit != this->arr->originating_curves_end(this->removableHalfedge)) - { - temp = ocit; - ++temp; - - Curve_handle ch = ocit; - Induced_edge_iterator itr; - for ( itr = this->arr->induced_edges_begin( ch ); - itr != this->arr->induced_edges_end( ch ); - ++itr ) - { - X_monotone_curve_2 curve = (*itr)->curve( ); - this->highlightedCurve->insert( curve ); - } - ocit = temp; - } - } - else - { // highlight just the edge - this->highlightedCurve->insert( this->removableHalfedge->curve( ) ); - } - - Q_EMIT modelChanged( ); -} + DeleteMode deleteMode; +}; #endif // DELETE_CURVE_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.cpp deleted file mode 100644 index e3157364bf8..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#include "DeleteCurveMode.h" - -#include - -DeleteCurveMode::DeleteCurveMode( ) : m_mode( DELETE_CURVE ) { } - -DeleteCurveMode::DeleteCurveMode( const DeleteCurveMode& dcm ) : - m_mode( dcm.mode( ) ) -{ } - -DeleteCurveMode::DeleteCurveMode( Mode mode ) : m_mode( mode ) { } - -DeleteCurveMode::~DeleteCurveMode( ) { } - -DeleteCurveMode::Mode DeleteCurveMode::mode( ) const -{ - return this->m_mode; -} - -void DeleteCurveMode::setMode( Mode mode ) -{ - this->m_mode = mode; -} - -QString DeleteCurveMode::ToString( const DeleteCurveMode& mode ) -{ - return ( mode.mode( ) == DELETE_CURVE ) ? - QString("Delete Curve") : QString("Delete Edge"); -} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.h deleted file mode 100644 index 44d80a0431c..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveMode.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef DELETE_CURVE_MODE_H -#define DELETE_CURVE_MODE_H - -#include - -class QString; - -/** -An attribute describing the policy for deleting curves from the arrangement. -*/ -class DeleteCurveMode -{ -public: - enum Mode { - DELETE_CURVE, - DELETE_EDGE - }; - - DeleteCurveMode( ); - DeleteCurveMode( const DeleteCurveMode& dcm ); - DeleteCurveMode( Mode mode ); - ~DeleteCurveMode( ); - - Mode mode( ) const; - void setMode( Mode mode ); - - static QString ToString( const DeleteCurveMode& mode ); - -protected: - Mode m_mode; -}; - -Q_DECLARE_METATYPE( DeleteCurveMode ) - -#endif // DELETE_CURVE_MODE_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.cpp deleted file mode 100644 index 241b19939d3..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#include "DeleteCurveModeItemEditor.h" - -DeleteCurveModeItemEditor::DeleteCurveModeItemEditor( QWidget* parent ) : - QComboBox( parent ) -{ - this->setFrame( false ); - - QVariant deleteCurveOption = QVariant::fromValue( DeleteCurveMode( ) ); - QVariant deleteEdgeOption = - QVariant::fromValue( DeleteCurveMode( DeleteCurveMode::DELETE_EDGE ) ); - this->insertItem( 0, "Delete Curve", deleteCurveOption ); - this->insertItem( 1, "Delete Edge", deleteEdgeOption ); -} - -DeleteCurveMode DeleteCurveModeItemEditor::mode( ) const -{ - return this->itemData(this->currentIndex( ), Qt::UserRole ).value< DeleteCurveMode >(); -} - -void DeleteCurveModeItemEditor::setMode( DeleteCurveMode m ) -{ - if ( m.mode( ) == DeleteCurveMode::DELETE_CURVE ) - { - this->setCurrentIndex( 0 ); - } - else - { - this->setCurrentIndex( 1 ); - } -} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.h deleted file mode 100644 index d1b2524df0a..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/DeleteCurveModeItemEditor.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef DELETE_CURVE_MODE_ITEM_EDITOR_H -#define DELETE_CURVE_MODE_ITEM_EDITOR_H - -#include -#include "DeleteCurveMode.h" - -class QWidget; - -class DeleteCurveModeItemEditor : public QComboBox -{ - Q_OBJECT - Q_PROPERTY( DeleteCurveMode mode READ mode WRITE setMode USER true ) - -public: - DeleteCurveModeItemEditor( QWidget* parent = 0 ); - -public: - DeleteCurveMode mode( ) const; - void setMode( DeleteCurveMode m ); - -}; // class DeleteCurveModeItemEditor - -#endif // DELETE_CURVE_MODE_ITEM_EDITOR_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp index f396826649e..71bb0f1d3c9 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,10 +7,286 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "EnvelopeCallback.h" +#include "CurveGraphicsItem.h" +#include "Utils/EnvelopeFunctions.h" +#include "Utils/Utils.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" + +#include +#include + +#include + +template +class EnvelopeCallback : public EnvelopeCallbackBase +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Point_2 Point_2; + + EnvelopeCallback(Arrangement* arr_, QObject* parent); + void showLowerEnvelope(bool show) override; + void showUpperEnvelope(bool show) override; + bool isUpperEnvelopeShown() override; + bool isLowerEnvelopeShown() override; + void reset() override; + + /** + Slot: Update and redraw the envelopes. + */ + void slotModelChanged() override; + + void setEnvelopeEdgeColor(const QColor& color) override; + const QColor& getEnvelopeEdgeColor() const override; + void setEnvelopeEdgeWidth(int width) override; + int getEnvelopeEdgeWidth() const override; + void setEnvelopeVertexColor(const QColor& color) override; + const QColor& getEnvelopeVertexColor() const override; + void setEnvelopeVertexRadius(int radius) override; + int getEnvelopeVertexRadius() const override; + +protected: + void setScene(QGraphicsScene* scene_) override; + void updateEnvelope(bool lower); + + Arrangement* arr; + CGAL::Qt::CurveGraphicsItem* lowerEnvelope; + CGAL::Qt::CurveGraphicsItem* upperEnvelope; + bool showLower; + bool showUpper; +}; // class EnvelopeCallback EnvelopeCallbackBase::EnvelopeCallbackBase( QObject* parent ) : CGAL::Qt::Callback( parent ) { } + +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new EnvelopeCallback(arr, parent); + } + + EnvelopeCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +EnvelopeCallbackBase* EnvelopeCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + EnvelopeCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +template +EnvelopeCallback::EnvelopeCallback(Arrangement* arr_, QObject* parent) : + EnvelopeCallbackBase(parent), arr(arr_), + lowerEnvelope(new CGAL::Qt::CurveGraphicsItem()), + upperEnvelope(new CGAL::Qt::CurveGraphicsItem()), showLower(false), + showUpper(false) +{ + this->lowerEnvelope->hide(); + this->upperEnvelope->hide(); +} + +template < typename Arr_ > +void EnvelopeCallback::setEnvelopeEdgeColor( const QColor& color ) +{ + this->lowerEnvelope->setEdgeColor( color ); + this->upperEnvelope->setEdgeColor( color ); +} + +template < typename Arr_ > +const QColor& EnvelopeCallback::getEnvelopeEdgeColor( ) const +{ + return this->lowerEnvelope->edgeColor( ); +} + +template < typename Arr_ > +void EnvelopeCallback::setEnvelopeEdgeWidth( int width ) +{ + this->lowerEnvelope->setEdgeWidth( width ); + this->upperEnvelope->setEdgeWidth( width ); +} + +template < typename Arr_ > +int EnvelopeCallback::getEnvelopeEdgeWidth( ) const +{ + return this->lowerEnvelope->edgeWidth( ); +} + +template < typename Arr_ > +void EnvelopeCallback::setEnvelopeVertexColor( const QColor& color ) +{ + this->lowerEnvelope->setVertexColor( color ); + this->upperEnvelope->setVertexColor( color ); +} + +template < typename Arr_ > +const QColor& EnvelopeCallback::getEnvelopeVertexColor( ) const +{ + return this->lowerEnvelope->vertexColor( ); +} + +template < typename Arr_ > +void EnvelopeCallback::setEnvelopeVertexRadius( int radius ) +{ + this->lowerEnvelope->setVertexRadius( radius ); + this->upperEnvelope->setVertexRadius( radius ); +} + +template < typename Arr_ > +int EnvelopeCallback::getEnvelopeVertexRadius( ) const +{ + return this->lowerEnvelope->vertexRadius( ); +} + +template < typename Arr_ > +void EnvelopeCallback::setScene( QGraphicsScene* scene_ ) +{ + EnvelopeCallbackBase::setScene(scene_); + lowerEnvelope->setScene(scene_); + upperEnvelope->setScene(scene_); + this->scene->addItem( this->lowerEnvelope ); + this->scene->addItem( this->upperEnvelope ); +} + +template < typename Arr_ > +void EnvelopeCallback< Arr_>::slotModelChanged( ) +{ + if (showLower) this->updateEnvelope(true); + if (showUpper) this->updateEnvelope(false); +} + +template < typename Arr_ > +void EnvelopeCallback< Arr_>::updateEnvelope( bool lower ) +{ + typedef CGAL::Envelope_diagram_1 Diagram_1; + typedef typename Diagram_1::Edge_const_handle Edge_const_handle; + + Diagram_1 diagram; + CGAL::Qt::CurveGraphicsItem* envelopeToUpdate; + + EnvelopeFunctions envelope_functions; + try + { + if (lower) + { + envelopeToUpdate = this->lowerEnvelope; + envelope_functions.lowerEnvelope(this->arr, diagram); + } + else + { + envelopeToUpdate = this->upperEnvelope; + envelope_functions.upperEnvelope(this->arr, diagram); + } + } + catch (const std::exception& ex) + { + std::cerr << ex.what() << '\n'; + std::cerr << __FILE__ << ':' << __LINE__ << '\n'; + if (lower) + this->showLowerEnvelope(false); + else + this->showUpperEnvelope(false); + return; + } + + envelopeToUpdate->clear( ); + + auto next_edge = [](const auto& e) -> Edge_const_handle { + auto&& v = e->right(); + if (v) return v->right(); + else return nullptr; + }; + + auto construct_x_monotone_subcurve_2 = + Construct_x_monotone_subcurve_2{arr->traits()}; + for (Edge_const_handle e = diagram.leftmost(); e; e = next_edge(e)) + { + if (!e->is_empty()) + { + boost::optional leftPoint, rightPoint; + if (e->left()) + leftPoint = e->left()->point(); + + if (e->right()) + rightPoint = e->right()->point(); + + X_monotone_curve_2 curve = + construct_x_monotone_subcurve_2(e->curve(), leftPoint, rightPoint); + + envelopeToUpdate->insert(curve); + // TODO: visually show leftPoint and rightPoint + // note: leftPoint and rightPoint are not the actual curve points + } + } + + envelopeToUpdate->modelChanged(); +} + +template < typename Arr_ > +void EnvelopeCallback< Arr_>::showLowerEnvelope( bool show ) +{ + this->showLower = show; + if (this->showLower) + { + this->updateEnvelope(true); + this->lowerEnvelope->show(); + } + else + { + this->lowerEnvelope->hide(); + } +} + +template < typename Arr_ > +void EnvelopeCallback< Arr_>::showUpperEnvelope( bool show ) +{ + this->showUpper = show; + if (this->showUpper) + { + this->updateEnvelope(false); + this->upperEnvelope->show(); + } + else + { + this->upperEnvelope->hide(); + } +} + +template +void EnvelopeCallback::reset() +{ + this->showLowerEnvelope(false); + this->showUpperEnvelope(false); +} + +template +bool EnvelopeCallback::isUpperEnvelopeShown() +{ + return this->showUpper; +} + +template +bool EnvelopeCallback::isLowerEnvelopeShown() +{ + return this->showLower; +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.h index cc8b95f6502..ed5f20e1ebf 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/EnvelopeCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,23 +7,29 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef ENVELOPE_CALLBACK_H #define ENVELOPE_CALLBACK_H #include "Callback.h" -#include "CurveGraphicsItem.h" +#include -#include -#include - -#include -#include "Utils.h" +namespace demo_types +{ +enum class TraitsType : int; +} +/** + Updates and draws the lower and upper envelopes of an observed arrangement. +*/ class EnvelopeCallbackBase : public CGAL::Qt::Callback { public: + static EnvelopeCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); + virtual void setEnvelopeEdgeColor( const QColor& color ) = 0; virtual const QColor& getEnvelopeEdgeColor( ) const = 0; virtual void setEnvelopeEdgeWidth( int width ) = 0; @@ -32,358 +38,13 @@ public: virtual const QColor& getEnvelopeVertexColor( ) const = 0; virtual void setEnvelopeVertexRadius( int radius ) = 0; virtual int getEnvelopeVertexRadius( ) const = 0; - -public Q_SLOTS: virtual void showLowerEnvelope( bool b ) = 0; virtual void showUpperEnvelope( bool b ) = 0; + virtual bool isUpperEnvelopeShown() = 0; + virtual bool isLowerEnvelopeShown() = 0; protected: EnvelopeCallbackBase( QObject* parent ); }; // class EnvelopeCallbackBase -/** - Updates and draws the lower and upper envelopes of an observed arrangement. -*/ -template < typename Arr_, typename Traits = typename Arr_::Geometry_traits_2 > -class EnvelopeCallback : public EnvelopeCallbackBase -{ -public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Edge_iterator Edge_iterator; - // typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - // typedef typename Traits::Construct_x_monotone_curve_2 - // Construct_x_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Kernel::Line_2 Line_2; - typedef CGAL::Envelope_diagram_1< Traits > Diagram_1; - - /** - Construct an envelope callback observing the given arrangement. - */ - EnvelopeCallback( Arrangement* arr_, QObject* parent ); - - /** - Enable/disable drawing the lower envelope. - */ - void showLowerEnvelope( bool show ); - - /** - Enable/disable drawing the lower envelope. - */ - void showUpperEnvelope( bool show ); - - /** - Slot: Update and redraw the envelopes. - */ - void slotModelChanged( ); - - void setEnvelopeEdgeColor( const QColor& color ) - { - this->lowerEnvelope->setEdgeColor( color ); - this->upperEnvelope->setEdgeColor( color ); - } - - const QColor& getEnvelopeEdgeColor( ) const - { - return this->lowerEnvelope->edgeColor( ); - } - - void setEnvelopeEdgeWidth( int width ) - { - this->lowerEnvelope->setEdgeWidth( width ); - this->upperEnvelope->setEdgeWidth( width ); - } - - int getEnvelopeEdgeWidth( ) const - { - return this->lowerEnvelope->edgeWidth( ); - } - - void setEnvelopeVertexColor( const QColor& color ) - { - this->lowerEnvelope->setVertexColor( color ); - this->upperEnvelope->setVertexColor( color ); - } - - const QColor& getEnvelopeVertexColor( ) const - { - return this->lowerEnvelope->vertexColor( ); - } - - void setEnvelopeVertexRadius( int radius ) - { - this->lowerEnvelope->setVertexRadius( radius ); - this->upperEnvelope->setVertexRadius( radius ); - } - - int getEnvelopeVertexRadius( ) const - { - return this->lowerEnvelope->vertexRadius( ); - } - - // shouldn't need this here, since it is in the base class Callback - // void setScene( QGraphicsScene* scene_ ); - -protected: - /** - Helper method to update the upper/lower envelope. - */ - void updateEnvelope( bool lower ); - - template < typename TTraits > - void updateEnvelope( bool lower, TTraits traits ); - - template < typename CircularKernel > - void updateEnvelope(bool lower, - CGAL::Arr_circular_arc_traits_2 traits); - - template < typename Coefficient_ > - void updateEnvelope(bool lower, - CGAL::Arr_algebraic_segment_traits_2 - traits); - - Construct_x_monotone_subcurve_2< Traits > construct_x_monotone_subcurve_2; - Arrangement* arr; - CGAL::Qt::CurveGraphicsItem< Traits >* lowerEnvelope; - CGAL::Qt::CurveGraphicsItem< Traits >* upperEnvelope; - using CGAL::Qt::Callback::scene; -}; // class EnvelopeCallback - -template < typename Arr_, typename Traits > -EnvelopeCallback::EnvelopeCallback(Arrangement* arr_, - QObject* parent) : - EnvelopeCallbackBase( parent ), - arr( arr_ ), - lowerEnvelope( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ), - upperEnvelope( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ) -{ - this->lowerEnvelope->hide( ); - this->upperEnvelope->hide( ); -} - -template < typename Arr_, typename Traits > -void EnvelopeCallback< Arr_, Traits >::slotModelChanged( ) -{ - this->updateEnvelope( true ); - this->updateEnvelope( false ); -} - -template < typename Arr_, typename Traits > -void EnvelopeCallback< Arr_, Traits >::updateEnvelope( bool lower ) -{ - this->updateEnvelope( lower, Traits( ) ); -} - -template < typename Arr_, typename Traits > -template < typename TTraits > -void EnvelopeCallback< Arr_, Traits >::updateEnvelope(bool lower, - TTraits /* traits */) -{ - CGAL::Qt::CurveGraphicsItem< Traits >* envelopeToUpdate; - if ( lower ) - { - envelopeToUpdate = this->lowerEnvelope; - } - else - { - envelopeToUpdate = this->upperEnvelope; - } - envelopeToUpdate->clear( ); - - std::list< X_monotone_curve_2 > curves; - Edge_iterator eit; - for (eit = this->arr->edges_begin( ); eit != this->arr->edges_end( ); ++eit) - { - curves.push_back( eit->curve( ) ); - } - Diagram_1 diagram; - if ( lower ) - { - CGAL::lower_envelope_x_monotone_2(curves.begin(), curves.end(), diagram); - } - else - { - CGAL::upper_envelope_x_monotone_2(curves.begin(), curves.end(), diagram); - } - - typename Diagram_1::Edge_const_handle e = diagram.leftmost( ); - typename Diagram_1::Vertex_const_handle v; - QRectF clipRect = this->viewportRect( ); - CGAL::Qt::Converter< Kernel > convert( clipRect ); - while ( e != diagram.rightmost( ) ) - { - if ( ! e->is_empty( ) ) - { - // The edge is not empty: draw a representative curve. - // Note that the we only draw the portion of the curve - // that overlaps the x-range defined by the two vertices - // that are incident to this edge. - - // TODO: generate a subcurve instead of just making a segment - - Point_2 leftPoint, rightPoint; - if ( e->left( ) != NULL ) - { - leftPoint = e->left( )->point( ); - } - else - { - // std::cout << "handle unbounded curve" << std::endl; - v = e->right( ); - e = v->right( ); - continue; - } - - if ( e->right( ) != NULL ) - { - rightPoint = e->right( )->point( ); - } - else - { - // std::cout << "pRight is null; should never get here..." - // << std::endl; - } - X_monotone_curve_2 curve = - this->construct_x_monotone_subcurve_2(e->curve(), - leftPoint, rightPoint); - envelopeToUpdate->insert( curve ); - envelopeToUpdate->insert( leftPoint ); - envelopeToUpdate->insert( rightPoint ); - } - v = e->right( ); - - // TODO: Draw the point associated with the current vertex. - e = v->right( ); - } - envelopeToUpdate->modelChanged( ); -} - -template < typename Arr_, typename Traits > -template < typename CircularKernel > -void EnvelopeCallback< Arr_, Traits >:: -updateEnvelope(bool lower, - CGAL::Arr_circular_arc_traits_2< CircularKernel > /* traits */) -{ - typedef typename Traits::Point_2 Arc_point_2; - CGAL::Qt::CurveGraphicsItem< Traits >* envelopeToUpdate; - if ( lower ) - { - envelopeToUpdate = this->lowerEnvelope; - } - else - { - envelopeToUpdate = this->upperEnvelope; - } - envelopeToUpdate->clear( ); - - std::list< X_monotone_curve_2 > curves; - for ( Edge_iterator eit = - this->arr->edges_begin( ); eit != this->arr->edges_end( ); ++eit ) - { - curves.push_back( eit->curve( ) ); - } - Diagram_1 diagram; - if ( lower ) - { - CGAL::lower_envelope_x_monotone_2( curves.begin(), curves.end(), diagram); - } - else - { - CGAL::upper_envelope_x_monotone_2(curves.begin( ), curves.end(), diagram); - } - - typename Diagram_1::Edge_const_handle e = diagram.leftmost( ); - typename Diagram_1::Vertex_const_handle v; - QRectF clipRect = this->viewportRect( ); - CGAL::Qt::Converter< Kernel > convert( clipRect ); - while ( e != diagram.rightmost( ) ) - { - if ( ! e->is_empty( ) ) - { - // The edge is not empty: draw a representative curve. - // Note that the we only draw the portion of the curve - // that overlaps the x-range defined by the two vertices - // that are incident to this edge. - - // TODO: generate a subcurve instead of just making a segment - - Arc_point_2 leftPoint, rightPoint; - if ( e->left( ) != NULL ) - { - leftPoint = e->left( )->point( ); - } - else - { - // std::cout << "handle unbounded curve" << std::endl; - v = e->right( ); - e = v->right( ); - continue; - } - - if ( e->right( ) != NULL ) - { - rightPoint = e->right( )->point( ); - } - else - { - // std::cout << "pRight is null; should never get here..." - // << std::endl; - } - X_monotone_curve_2 curve = - this->construct_x_monotone_subcurve_2( e->curve( ), - leftPoint, rightPoint ); - envelopeToUpdate->insert( curve ); - } - v = e->right( ); - - // TODO: Draw the point associated with the current vertex. - e = v->right( ); - } - envelopeToUpdate->modelChanged( ); -} - -template < typename Arr_, typename Traits > -template < typename Coefficient_ > -void EnvelopeCallback< Arr_, Traits >:: -updateEnvelope(bool /* lower */, - CGAL::Arr_algebraic_segment_traits_2 /* traits */) -{ - // std::cout << "alg seg envelope stub" << std::endl; -} - -template < typename Arr_, typename Traits > -void EnvelopeCallback< Arr_, Traits >::showLowerEnvelope( bool show ) -{ - if ( show ) - { - // std::cout << "Show lower envelope" << std::endl; - this->scene->addItem( this->lowerEnvelope ); - } - else - { - // std::cout << "Hide lower envelope" << std::endl; - this->scene->removeItem( this->lowerEnvelope ); - } -} - -template < typename Arr_, typename Traits > -void EnvelopeCallback< Arr_, Traits >::showUpperEnvelope( bool show ) -{ - if ( show ) - { - // std::cout << "Show upper envelope" << std::endl; - this->scene->addItem( this->upperEnvelope ); - } - else - { - // std::cout << "Hide upper envelope" << std::endl; - this->scene->removeItem( this->upperEnvelope ); - } -} - #endif // ENVELOPE_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.cpp index b597f203d04..992110aa29e 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,22 +7,115 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "FillFaceCallback.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "Utils/PointLocationFunctions.h" +#include "Utils/Utils.h" -FillFaceCallbackBase::FillFaceCallbackBase( QObject* parent ) : - CGAL::Qt::Callback( parent ), - fillColor( ::Qt::black ) -{ } +#include -void FillFaceCallbackBase::setColor( QColor c ) +template +class FillFaceCallback : public FillFaceCallbackBase +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Face_handle Face_handle; + typedef typename Arrangement::Face_const_handle Face_const_handle; + + FillFaceCallback(Arrangement* arr_, QObject* parent_); + void reset(); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + void fillFace(QGraphicsSceneMouseEvent* event); + + Arrangement* arr; +}; // class FillFaceCallback + +FillFaceCallbackBase::FillFaceCallbackBase(QObject* parent) : + CGAL::Qt::Callback(parent), fillColor(::Qt::black) +{ +} + +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new FillFaceCallback(arr, parent); + } + + FillFaceCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +FillFaceCallbackBase* FillFaceCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + FillFaceCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +void FillFaceCallbackBase::setColor(QColor c) { this->fillColor = c; - Q_EMIT modelChanged( ); + Q_EMIT modelChanged(); } -QColor FillFaceCallbackBase::getColor( ) const +QColor FillFaceCallbackBase::getColor() const { return this->fillColor; } + +template +FillFaceCallback::FillFaceCallback(Arrangement* arr_, QObject* parent_) : + FillFaceCallbackBase(parent_), + arr(arr_) { - return this->fillColor; +} + +template +void FillFaceCallback::reset() +{ +} + +template +void FillFaceCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + this->fillFace(event); + Q_EMIT modelChanged(); +} + +template +void FillFaceCallback::mouseMoveEvent( + QGraphicsSceneMouseEvent* /* event */) +{ +} + +template +void FillFaceCallback::fillFace(QGraphicsSceneMouseEvent* event) +{ + if (!this->fillColor.isValid()) + return; + + Face_const_handle face = + PointLocationFunctions{}.getFace(arr, event->scenePos()); + + Face_handle f = this->arr->non_const_handle(face); + + if (f->color() != this->fillColor) + f->set_color(this->fillColor); + else + f->set_color(::Qt::white); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.h index da5251917f2..e88f534c44b 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FillFaceCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,227 +7,39 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef FILL_FACE_CALLBACK_H #define FILL_FACE_CALLBACK_H #include "Callback.h" +#include +#include -#include -#include -#include -#include -#include -#include "CurveGraphicsItem.h" -#include -#include -#include -#include -#include -#include +namespace demo_types +{ +enum class TraitsType : int; +} -#include "Utils.h" +class QGraphicsSceneMouseEvent; +/** + Supports visualization of point location on arrangements. +*/ class FillFaceCallbackBase : public CGAL::Qt::Callback { public: - FillFaceCallbackBase( QObject* parent ); + static FillFaceCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); void setColor( QColor c ); QColor getColor( ) const; protected: + FillFaceCallbackBase( QObject* parent ); + QColor fillColor; }; -/** - Supports visualization of point location on arrangements. - - The template parameter is a CGAL::Arrangement_with_history_2 of some type. -*/ -template < class Arr_ > -class FillFaceCallback : public FillFaceCallbackBase -{ -public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Face_handle Face_handle; - typedef typename Arrangement::Face_const_handle Face_const_handle; - typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Arrangement::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename CGAL::Arr_trapezoid_ric_point_location< Arrangement > - TrapezoidPointLocationStrategy; - typedef typename CGAL::Arr_simple_point_location< Arrangement > - SimplePointLocationStrategy; - typedef typename CGAL::Arr_walk_along_line_point_location< Arrangement > - Walk_pl_strategy; - typedef typename Supports_landmarks< Arrangement >::LandmarksType - LandmarksPointLocationStrategy; - - FillFaceCallback( Arrangement* arr_, QObject* parent_ ); - void reset( ); - - -protected: - void mousePressEvent( QGraphicsSceneMouseEvent *event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent *event ); - - void fillFace( QGraphicsSceneMouseEvent* event ); - - Face_const_handle getFace( const CGAL::Object& o ); - CGAL::Object locate( const Kernel_point_2& point ); - CGAL::Object locate( const Kernel_point_2& point, - CGAL::Tag_false/*supportsLandmarks*/ ); - CGAL::Object locate( const Kernel_point_2& point, - CGAL::Tag_true /*doesNotSupportLandmarks*/ ); - - CGAL::Qt::Converter< Kernel > convert; - CGAL::Object pointLocationStrategy; - Arrangement* arr; - Arr_construct_point_2< Traits > toArrPoint; -}; // class FillFaceCallback - -/*! Constructor */ -template < class Arr_ > -FillFaceCallback::FillFaceCallback(Arrangement* arr_, QObject* parent_): - FillFaceCallbackBase( parent_ ), - pointLocationStrategy( CGAL::make_object( new Walk_pl_strategy( *arr_ ) ) ), - arr( arr_ ) -{ } - -template < class Arr_ > -void FillFaceCallback< Arr_ >::reset( ) -{ - Q_EMIT modelChanged( ); -} - -template < class Arr_ > -void FillFaceCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - this->fillFace( event ); - Q_EMIT modelChanged( ); -} - -template < class Arr_ > -void -FillFaceCallback< Arr_ >::mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) -{ } - -template < class Arr_ > -void -FillFaceCallback< Arr_ >:: -fillFace( QGraphicsSceneMouseEvent* event ) -{ - Kernel_point_2 point = this->convert( event->scenePos( ) ); - CGAL::Object pointLocationResult = this->locate( point ); - Face_const_handle face = this->getFace( pointLocationResult ); - Face_handle f = this->arr->non_const_handle( face ); - if ( this->fillColor.isValid( ) ) - { - f->set_color( this->fillColor ); - } -} - -template < class Arr_ > -typename FillFaceCallback< Arr_ >::Face_const_handle -FillFaceCallback< Arr_ >::getFace( const CGAL::Object& obj ) -{ - Face_const_handle f; - if ( CGAL::assign( f, obj ) ) - return f; - - Halfedge_const_handle he; - if (CGAL::assign( he, obj )) - return (he->face( )); - - Vertex_const_handle v; - CGAL_assertion(CGAL::assign( v, obj )); - CGAL::assign( v, obj ); - if ( v->is_isolated( ) ) - return v->face( ); - Halfedge_around_vertex_const_circulator eit = v->incident_halfedges( ); - return (eit->face( )); -} - -template < class Arr_ > -CGAL::Object FillFaceCallback< Arr_ >::locate( const Kernel_point_2& point ) -{ - typename Supports_landmarks< Arrangement >::Tag supportsLandmarks; - return this->locate( point, supportsLandmarks ); -} - -template < class Arr_ > -CGAL::Object -FillFaceCallback< Arr_ >::locate( const Kernel_point_2& pt, CGAL::Tag_true ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - LandmarksPointLocationStrategy* landmarksStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->locate( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->locate( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->locate( point ); - } - else if ( CGAL::assign( landmarksStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = landmarksStrategy->locate( point ); - } - return pointLocationResult; -} - -template < class Arr_ > -CGAL::Object -FillFaceCallback< Arr_ >::locate( const Kernel_point_2& pt, CGAL::Tag_false ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->locate( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->locate( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->locate( point ); - } - return pointLocationResult; -} - #endif // FILL_FACE_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.cpp new file mode 100644 index 00000000000..04f75f85243 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.cpp @@ -0,0 +1,86 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "FloodFill.h" + +namespace CGAL +{ +namespace Qt +{ + +void FloodFill::operator()( + QRgb* raw_img, uint16_t width, uint16_t x, uint16_t y, QRgb color) +{ + const QRgb old_val = raw_img[y * width + x]; + + auto fill_line = [&fill_stack=(this->fill_stack), raw_img, old_val, width] + (QRgb color, uint16_t prev_left, uint16_t prev_right, uint16_t y, int16_t dy) + { + QRgb* img_line = raw_img + y * width; + + for (uint16_t i = prev_left; i < prev_right; i++) + { + if (img_line[i] == old_val) + { + uint16_t j = i; + + img_line[i] = color; + while (img_line[--j] == old_val) img_line[j] = color; + while (img_line[++i] == old_val) img_line[i] = color; + + uint16_t left = j + 1; + uint16_t right = static_cast(i - 1); + + fill_stack.push_back({y, left, right, prev_left, prev_right, dy}); + } + } + }; + + // first iteration + do + { + uint16_t left = x; + uint16_t right = x; + + QRgb* img_line = raw_img + y * width; + img_line[left] = color; + while (img_line[--left] == old_val) img_line[left] = color; + while (img_line[++right] == old_val) img_line[right] = color; + ++left; + --right; + + this->fill_stack.push_back( + {y, left, right, static_cast(right + 1), right, 1}); + + } while (false); + + while (!this->fill_stack.empty()) + { + auto line = fill_stack.back(); + this->fill_stack.pop_back(); + + auto ly = line.y; + auto ll = line.left; + auto lr = line.right; + auto lpl = line.prev_left; + auto lpr = line.prev_right; + auto ldy = line.dy; + + // fill line in the new y direction + fill_line(color, ll, lr, ly + ldy, ldy); + // revisit the old fill line in the remaining bits + fill_line(color, lpr + 1, lr, ly - ldy, -ldy); + fill_line(color, ll, lpl - 1, ly - ldy, -ldy); + } +} + +} // namespace Qt +} // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.h new file mode 100644 index 00000000000..160b6c6477d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/FloodFill.h @@ -0,0 +1,60 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_FLOOD_FILL_H +#define ARRANGEMENT_DEMO_FLOOD_FILL_H + +#include +#include + +namespace CGAL +{ +namespace Qt +{ + +// scanline flood fill +class FloodFill +{ +public: + // this currently assumes that there is a "border" in the boundaries that + // will prevent the flood fill from going there + // this way we don't check bounadry conditions! + void + operator()(QRgb* raw_img, uint16_t width, uint16_t x, uint16_t y, QRgb color); + +private: + struct FillLine + { + uint16_t y; + uint16_t left; + uint16_t right; + uint16_t prev_left; + uint16_t prev_right; + // y = prev_y + dy + int16_t dy; + + FillLine( + uint16_t y_, uint16_t left_, uint16_t right_, uint16_t prev_left_, + uint16_t prev_right_, int16_t dy_) : + y{y_}, + left{left_}, right{right_}, prev_left{prev_left_}, + prev_right{prev_right_}, dy{dy_} + { + } + }; + + std::vector fill_stack; +}; + +} // namespace Qt +} // namespace CGAL + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ForwardDeclarations.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ForwardDeclarations.h new file mode 100644 index 00000000000..72c663d750c --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ForwardDeclarations.h @@ -0,0 +1,75 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef CGAL_ARRANGEMENT_DEMO_FORWARD_DECLARATION_H +#define CGAL_ARRANGEMENT_DEMO_FORWARD_DECLARATION_H + +namespace CGAL +{ + +// Arrangement Traits +template +class Arr_segment_traits_2; + +template +class Arr_linear_traits_2; + +template +class Arr_polyline_traits_2; + +template +class Arr_conic_traits_2; + +template < + typename RatKernel_, typename AlgKernel_, typename NtTraits_, + typename BoundingTraits_> +class Arr_Bezier_curve_traits_2; + +template +class Arr_algebraic_segment_traits_2; + +template +class Arr_rational_function_traits_2; + +template < + class RatKernel_, class AlgKernel_, class NtTraits_, class BoundingTraits_> +class _Bezier_point_2; + +// Tags +struct Arr_boundary_side_tag; +struct Arr_oblivious_side_tag; +struct Arr_open_side_tag; +struct Arr_closed_side_tag; +struct Arr_contracted_side_tag; +struct Arr_identified_side_tag; + +template +class Rational_traits; + +template +struct Cartesian; + +class Object; + +namespace Qt +{ +class CurveInputMethod; +} + +} // namespace CGAL + +namespace demo_types +{ +enum class TraitsType : int; +struct DemoTypes; +} + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.cpp new file mode 100644 index 00000000000..c38d4685b73 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include "GraphicsSceneMixin.h" +#include +#include + +GraphicsSceneMixin::GraphicsSceneMixin(QGraphicsScene* scene_) : scene{scene_} +{ +} + +GraphicsSceneMixin::~GraphicsSceneMixin() { } + +void GraphicsSceneMixin::setScene(QGraphicsScene* scene_) +{ + this->scene = scene_; +} + +QGraphicsScene* GraphicsSceneMixin::getScene() const { return this->scene; } + +QRectF GraphicsSceneMixin::viewportRect() const +{ + QGraphicsView* view = this->getView(); + return view ? view->mapToScene(QRect{0, 0, view->width(), view->height()}) + .boundingRect() + : QRectF{}; +} + +QPoint GraphicsSceneMixin::fromScene(QPointF p) +{ + QGraphicsView* viewport = this->getView(); + return viewport ? viewport->mapFromScene(p) : QPoint{}; +} + +QPointF GraphicsSceneMixin::toScene(QPoint p) const +{ + QGraphicsView* viewport = this->getView(); + return viewport ? viewport->mapToScene(p) : QPointF{}; +} + +QGraphicsView* GraphicsSceneMixin::getView() const +{ + if (!this->scene) return nullptr; + + QList views = this->scene->views(); + if (views.size() == 0) return nullptr; + // assumes the first view is the right one + return views.first(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.h new file mode 100644 index 00000000000..6e79b95939f --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsSceneMixin.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#ifndef CGAL_ARRANGEMENTS_DEMO_GRAPHICS_SCENE_MIXIN_H +#define CGAL_ARRANGEMENTS_DEMO_GRAPHICS_SCENE_MIXIN_H + +#include +#include +#include + +class QGraphicsScene; +class QGraphicsView; + +class GraphicsSceneMixin +{ +public: + /*! Costructor */ + GraphicsSceneMixin(QGraphicsScene* scene_ = nullptr); + + /*! Destructor (virtual) */ + virtual ~GraphicsSceneMixin(); + virtual void setScene(QGraphicsScene* scene_); + QGraphicsScene* getScene() const; + QRectF viewportRect() const; + QPoint fromScene(QPointF p); + QPointF toScene(QPoint p) const; + QGraphicsView* getView() const; + +protected: // fields + QGraphicsScene* scene; +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp index 6650e582ad4..45efa1e73af 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,115 +7,518 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "GraphicsViewCurveInput.h" +#include "AlgebraicCurveParser.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveInputMethods.h" +#include "GraphicsViewCurveInputTyped.h" +#include "QtMetaTypes.h" +#include "Utils/Utils.h" -#include +#include -namespace CGAL { -namespace Qt { +#include +#include -void GraphicsViewCurveInputBase::setScene( QGraphicsScene* scene_ ) +template +inline typename std::enable_if::type +for_each(std::tuple&, FuncT) { - this->QGraphicsSceneMixin::setScene( scene_ ); - if ( this->scene != NULL ) +} + +template + inline typename std::enable_if < + I::type for_each(std::tuple& t, FuncT f) +{ + f(std::get(t)); + for_each(t, f); +} + +namespace CGAL +{ +namespace Qt +{ + +GraphicsViewCurveInputBase::GraphicsViewCurveInputBase( + QObject* parent, QGraphicsScene* scene) : + Callback(parent, scene), + inputMethod(nullptr) +{ +} + +void GraphicsViewCurveInputBase::setInputMethod(CurveInputMethod* inputMethod_) +{ + this->inputMethod = inputMethod_; +} + +void GraphicsViewCurveInputBase::reset() +{ + if (this->inputMethod) { - this->scene->addItem( &this->pointsGraphicsItem ); + this->inputMethod->reset(); + this->inputMethod = nullptr; } } -#if 0 -QGraphicsScene* GraphicsViewCurveInputBase::getScene( ) const +bool GraphicsViewCurveInputBase::eventFilter(QObject* obj, QEvent* event) { - return this->scene; -} -#endif - -void GraphicsViewCurveInputBase::setSnappingEnabled( bool b ) -{ - this->snappingEnabled = b; + return this->inputMethod->eventFilter(obj, event); } -void GraphicsViewCurveInputBase::setSnapToGridEnabled( bool b ) +void GraphicsViewCurveInputBase::setColor(QColor c) { - this->snapToGridEnabled = b; + this->inputMethod->setColor(c); } -/*! Constructor */ -GraphicsViewCurveInputBase::GraphicsViewCurveInputBase( QObject* parent ) : - GraphicsViewInput( parent ), -// scene( NULL ), - snappingEnabled( false ), - snapToGridEnabled( false ), - color( ::Qt::blue ) +template +GraphicsViewCurveInput::GraphicsViewCurveInput( + Arrangement* arrangement_, QObject* parent, QGraphicsScene* scene) : + GraphicsViewCurveInputBase(parent, scene), + arrangement(arrangement_) { - this->pointsGraphicsItem.setZValue( 100 ); - this->pointsGraphicsItem.setColor( this->color ); + this->setDefaultInputMethod( + std::integral_constant< + bool, std::tuple_size::value != 0>{}); + for_each(inputMethods, [&](auto&& it) { + it.setScene(scene); + it.setCallback(this); + }); + curveGenerator.setTraits(this->arrangement->traits()); } -void -GraphicsViewCurveInputBase::mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) -{ } - -void GraphicsViewCurveInputBase:: -mousePressEvent(QGraphicsSceneMouseEvent* /* event */) +template +void GraphicsViewCurveInput::setCurveType(CurveType type) { - // std::cout << "GraphicsViewCurveInputBase::mousePressEvent" << std::endl; + this->reset(); + for_each(inputMethods, [&](auto&& it) { + if (it.curveType() == type) + this->setInputMethod(static_cast(&it)); + }); } -bool GraphicsViewCurveInputBase::eventFilter( QObject* obj, QEvent* event ) +template +void GraphicsViewCurveInput::setPointSnapper(PointSnapperBase* snapper_) { - if ( event->type( ) == QEvent::GraphicsSceneMouseMove ) + for_each(inputMethods, [&](auto&& it) { it.setPointSnapper(snapper_); }); +} + +template +template +void GraphicsViewCurveInput::setDefaultInputMethod(std::true_type) +{ + this->setInputMethod(&std::get<0>(inputMethods)); +} + +template +void GraphicsViewCurveInput::setDefaultInputMethod(std::false_type) +{ +} + +template +void GraphicsViewCurveInput::generate(CGAL::Object o) +{ + insertCurve( + demo_types::enumFromArrType(), + CGAL::make_object(this->arrangement), o); + Q_EMIT CGAL::Qt::GraphicsViewCurveInputBase::modelChanged(); +} + +template +void GraphicsViewCurveInput::curveInputDoneEvent( + const std::vector& clickedPoints, CurveType type) +{ + boost::optional cv = + this->curveGenerator.generate(clickedPoints, type); + if (cv) { - QGraphicsSceneMouseEvent* mouseEvent = - static_cast< QGraphicsSceneMouseEvent* >( event ); - this->mouseMoveEvent( mouseEvent ); + Insert_curve{}(this->arrangement, *cv); + Q_EMIT this->modelChanged(); } - else if ( event->type( ) == QEvent::GraphicsSceneMousePress ) - { - QGraphicsSceneMouseEvent* mouseEvent = - static_cast< QGraphicsSceneMouseEvent* >( event ); - this->mousePressEvent( mouseEvent ); - } - - return QObject::eventFilter( obj, event ); } -void GraphicsViewCurveInputBase::setColor( QColor c ) +// CurveGeneratorBase +template +auto CurveGeneratorBase::generate( + const std::vector& clickedPoints, CurveType type) + -> boost::optional { - this->color = c; - this->pointsGraphicsItem.setColor( this->color ); -} - -QColor GraphicsViewCurveInputBase::getColor( ) const -{ - return this->color; -} - -#if 0 -QRectF GraphicsViewCurveInputBase::viewportRect( ) const -{ - QRectF res; - if ( this->scene == NULL ) + boost::optional res; + switch (type) { - return res; + case CurveType::Segment: + res = generateSegment(clickedPoints); + break; + case CurveType::Ray: + res = generateRay(clickedPoints); + break; + case CurveType::Line: + res = generateLine(clickedPoints); + break; + case CurveType::Polyline: + res = generatePolyline(clickedPoints); + break; + case CurveType::Circle: + res = generateCircle(clickedPoints); + break; + case CurveType::Ellipse: + res = generateEllipse(clickedPoints); + break; + case CurveType::ThreePointCircularArc: + res = generateThreePointCircularArc(clickedPoints); + break; + case CurveType::FivePointConicArc: + res = generateFivePointConicArc(clickedPoints); + break; + case CurveType::Bezier: + res = generateBezier(clickedPoints); + default: + break; } - - QList< QGraphicsView* > views = this->scene->views( ); - if ( views.size( ) == 0 ) - { - return res; - } - // assumes the first view is the right one - QGraphicsView* viewport = views.first( ); - QPointF p1 = viewport->mapToScene( 0, 0 ); - QPointF p2 = viewport->mapToScene( viewport->width( ), viewport->height( ) ); - res = QRectF( p1, p2 ); - return res; } -#endif + +template +void CurveGeneratorBase::setTraits(const ArrTraits* traits_) +{ + this->traits = traits_; +} + +// Curve Generator Segment Traits +template +auto CurveGenerator>::generateSegment( + const std::vector& clickedPoints) -> boost::optional +{ + Curve_2 res{clickedPoints[0], clickedPoints[1]}; + return res; +} + +// Curve Generator Polyline Traits +template +auto CurveGenerator>:: + generatePolyline(const std::vector& clickedPoints) + -> boost::optional +{ + if (clickedPoints.size() < 2) return {}; + + auto construct_poly = this->traits->construct_curve_2_object(); + Curve_2 res = construct_poly(clickedPoints.begin(), clickedPoints.end()); + return res; +} + +// Curve Generator Linear Traits +template +auto CurveGenerator>::generateSegment( + const std::vector& points) -> boost::optional +{ + Curve_2 res = Curve_2(Segment_2(points[0], points[1])); + return res; +} + +template +auto CurveGenerator>::generateRay( + const std::vector& points) -> boost::optional +{ + Curve_2 res = Curve_2(Ray_2(points[0], points[1])); + return res; +} + +template +auto CurveGenerator>::generateLine( + const std::vector& points) -> boost::optional +{ + Curve_2 res = Curve_2(Line_2(points[0], points[1])); + return res; +} + +// CurveGenerator Conic Traits +template +auto CurveGenerator>:: + generateSegment(const std::vector& points) + -> boost::optional +{ + Curve_2 res = Curve_2(Rat_segment_2(points[0], points[1])); + return res; +} + +template +auto CurveGenerator>:: + generateCircle(const std::vector& points) -> boost::optional +{ + auto sq_rad = + (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) + + (points[0].y() - points[1].y()) * (points[0].y() - points[1].y()); + Curve_2 res = Curve_2(Rat_circle_2(points[0], sq_rad)); + return res; +} + +template +auto CurveGenerator>:: + generateEllipse(const std::vector& points) + -> boost::optional +{ + auto x1 = (CGAL::min)(points[0].x(), points[1].x()); + auto y1 = (CGAL::min)(points[0].y(), points[1].y()); + auto x2 = (CGAL::max)(points[0].x(), points[1].x()); + auto y2 = (CGAL::max)(points[0].y(), points[1].y()); + + Rat_FT a = CGAL::abs(Rat_FT(x1) - Rat_FT(x2)) / 2; + Rat_FT b = CGAL::abs(Rat_FT(y1) - Rat_FT(y2)) / 2; + Rat_FT a_sq = a * a; + Rat_FT b_sq = b * b; + Rat_FT x0 = (x2 + x1) / 2; + Rat_FT y0 = (y2 + y1) / 2; + + Rat_FT r = b_sq; + Rat_FT s = a_sq; + Rat_FT t = 0; + Rat_FT u = -2 * x0 * b_sq; + Rat_FT v = -2 * y0 * a_sq; + Rat_FT ww = x0 * x0 * b_sq + y0 * y0 * a_sq - a_sq * b_sq; + + Curve_2 res = Curve_2(r, s, t, u, v, ww); + return res; +} + +template +auto CurveGenerator>:: + generateThreePointCircularArc(const std::vector& points) + -> boost::optional +{ + auto& qp1 = points[0]; + auto& qp2 = points[1]; + auto& qp3 = points[2]; + Rat_point_2 p1 = Rat_point_2(qp1.x(), qp1.y()); + Rat_point_2 p2 = Rat_point_2(qp2.x(), qp2.y()); + Rat_point_2 p3 = Rat_point_2(qp3.x(), qp3.y()); + RatKernel ker; + if (!ker.collinear_2_object()(p1, p2, p3)) + { + Curve_2 res(p1, p2, p3); + return res; + } + else + { + std::cout << "Points don't specify a valid conic." << std::endl; + return {}; + } +} + +template +auto CurveGenerator>:: + generateFivePointConicArc(const std::vector& points) + -> boost::optional +{ + auto& qp0 = points[0]; + auto& qp1 = points[1]; + auto& qp2 = points[2]; + auto& qp3 = points[3]; + auto& qp4 = points[4]; + Rat_point_2 p0 = Rat_point_2(qp0.x(), qp0.y()); + Rat_point_2 p1 = Rat_point_2(qp1.x(), qp1.y()); + Rat_point_2 p2 = Rat_point_2(qp2.x(), qp2.y()); + Rat_point_2 p3 = Rat_point_2(qp3.x(), qp3.y()); + Rat_point_2 p4 = Rat_point_2(qp4.x(), qp4.y()); + try + { + Curve_2 res(p0, p1, p2, p3, p4); + if (res.is_valid()) + return res; + else + std::cout << "Points don't specify a valid conic. Try again!" + << std::endl; + } + catch (...) + { + std::cout << "Points don't specify a valid conic. Try again!" << std::endl; + } + return {}; +} + +// CurveGenerator Algebraic Traits +template +auto CurveGenerator>:: + generateLine(const std::vector& points) -> boost::optional +{ + RationalTraits ratTraits; + + Rational dx = points[1].x() - points[0].x(); + Rational dy = points[1].y() - points[0].y(); + Polynomial_2 x = CGAL::shift(Polynomial_2(1), 1, 0); + Polynomial_2 y = CGAL::shift(Polynomial_2(1), 1, 1); + + Polynomial_2 poly; + if (dx != 0) + { + Rational mRat = dy / dx; + Rational cRat = points[0].y() - mRat * points[0].x(); + // y = (a/b) x + (e/f) + auto a = ratTraits.numerator(mRat); + auto b = ratTraits.denominator(mRat); + auto e = ratTraits.numerator(cRat); + auto f = ratTraits.denominator(cRat); + + poly = b * f * y - f * a * x - b * e; + } + // vertical line + else + { + Rational xP = points[0].x(); + auto a = ratTraits.numerator(xP); + auto b = ratTraits.denominator(xP); + poly = b * x - a; + } + + auto construct_curve = this->traits->construct_curve_2_object(); + auto res = construct_curve(poly); + return res; +} + +template +auto CurveGenerator>:: + generateCircle(const std::vector& points) -> boost::optional +{ + auto sq_rad = + (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) + + (points[0].y() - points[1].y()) * (points[0].y() - points[1].y()); + return this->generateEllipse_(points[0], sq_rad, sq_rad); +} + +template +auto CurveGenerator>:: + generateEllipse(const std::vector& points) + -> boost::optional +{ + auto rx = + (points[0].x() - points[1].x()) * (points[0].x() - points[1].x()) / 4.; + auto ry = + (points[0].y() - points[1].y()) * (points[0].y() - points[1].y()) / 4.; + Point_2 center = { + (points[1].x() + points[0].x()) / 2, (points[1].y() + points[0].y()) / 2}; + return this->generateEllipse_(center, rx, ry); +} + +template +auto CurveGenerator>:: + generateEllipse_(const Point_2& center, Rational rxRat, Rational ryRat) + -> boost::optional +{ + RationalTraits ratTraits; + + Polynomial_2 x = CGAL::shift(Polynomial_2(1), 1, 0); + Polynomial_2 y = CGAL::shift(Polynomial_2(1), 1, 1); + Rational xCenter = center.x(); + Rational yCenter = center.y(); + + // (g/h) (x - a/b)^2 + (e/f) (y - c/d)^2 = (e/f) * (g/h) + auto a = ratTraits.numerator(xCenter); + auto b = ratTraits.denominator(xCenter); + auto c = ratTraits.numerator(yCenter); + auto d = ratTraits.denominator(yCenter); + auto e = ratTraits.numerator(rxRat); + auto f = ratTraits.denominator(rxRat); + auto g = ratTraits.numerator(ryRat); + auto h = ratTraits.denominator(ryRat); + + Polynomial_2 poly = g * f * CGAL::ipower(b * d * x - d * a, 2) + + e * h * CGAL::ipower(b * d * y - b * c, 2) - + e * g * b * b * d * d; + + auto construct_curve = this->traits->construct_curve_2_object(); + auto res = construct_curve(poly); + return res; +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto CurveGenerator< + Arr_Bezier_curve_traits_2>:: + generateBezier(const std::vector& clickedPoints) + -> boost::optional +{ + if (clickedPoints.size() < 2) return {}; + return Curve_2{clickedPoints.begin(), clickedPoints.end()}; +} + +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new GraphicsViewCurveInput(arr, parent, scene); + } + + GraphicsViewCurveInputBase*& res; + CGAL::Object& arr_obj; + QObject* parent; + QGraphicsScene* scene; +}; +} // anonymous namespace + +GraphicsViewCurveInputBase* GraphicsViewCurveInputBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent, + QGraphicsScene* scene) +{ + GraphicsViewCurveInputBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent, scene}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} } // namespace Qt } // namespace CGAL + +#ifdef CGAL_USE_CORE +CGAL::Object algebraicCurveFromExpression( + const CGAL::Object& arr_obj, const std::string& exp, bool& is_first_curve) +{ + using Polynomial_2 = demo_types::DemoTypes::Alg_seg_traits::Polynomial_2; + using Alg_seg_arr = demo_types::DemoTypes::Alg_seg_arr; + + Alg_seg_arr* arr; + if (!CGAL::assign(arr, arr_obj)) CGAL_error(); + + is_first_curve = (arr->number_of_edges() == 0); + + auto poly = AlgebraicCurveParser{}(exp); + if (!poly) return {}; + + auto construct_curve = arr->traits()->construct_curve_2_object(); + auto cv = construct_curve(*poly); + + return CGAL::make_object(cv); +} + +CGAL::Object rationalCurveFromExpression( + const CGAL::Object& arr_obj, const std::string& numerator, + const std::string& denominator, bool& is_first_curve) +{ + using Polynomial_1 = demo_types::DemoTypes::Rational_traits::Polynomial_1; + using Rational_arr = demo_types::DemoTypes::Rational_arr; + + Rational_arr* arr; + if (!CGAL::assign(arr, arr_obj)) CGAL_error(); + + is_first_curve = (arr->number_of_edges() == 0); + + auto curve_parser = AlgebraicCurveParser{}; + auto poly_num = curve_parser(numerator); + if (!poly_num) return {}; + auto poly_den = curve_parser(denominator); + if (!poly_den) return {}; + + auto construct_curve = arr->traits()->construct_curve_2_object(); + auto cv = construct_curve(*poly_num, *poly_den); + + return CGAL::make_object(cv); +} +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.h index 24b92af7e36..3528a7e8505 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInput.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,906 +7,69 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui , +// Saurabh Singh +// Ahmed Essam #ifndef CGAL_QT_GRAPHICS_VIEW_CURVE_INPUT_H #define CGAL_QT_GRAPHICS_VIEW_CURVE_INPUT_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "Callback.h" -#include "ISnappable.h" -#include "PointsGraphicsItem.h" +#include "ForwardDeclarations.h" -namespace CGAL { -namespace Qt { +class QEvent; +class PointSnapperBase; -class GraphicsViewCurveInputBase : - public GraphicsViewInput, public ISnappable, public QGraphicsSceneMixin +namespace demo_types { -public: - /** - Add our helper graphics items to the scene. - @override - */ - virtual void setScene( QGraphicsScene* scene_ ); - //virtual QGraphicsScene* getScene( ) const; +enum class TraitsType : int; +} - void setSnappingEnabled( bool b ); - void setSnapToGridEnabled( bool b ); - virtual void setColor( QColor c ); - QColor getColor( ) const; +namespace CGAL +{ +namespace Qt +{ + +class CurveInputMethod; +enum class CurveType : int; + +class GraphicsViewCurveInputBase : public Callback +{ + Q_OBJECT + +public: + static GraphicsViewCurveInputBase* create( + demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent, + QGraphicsScene* scene); + + void setColor(QColor c); + void reset() override; + bool eventFilter(QObject* obj, QEvent* event) override; + virtual void setCurveType(CurveType type) = 0; + virtual void setPointSnapper(PointSnapperBase*) = 0; + virtual void generate(CGAL::Object) = 0; protected: - GraphicsViewCurveInputBase( QObject* parent ); - virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event ); - virtual void mousePressEvent( QGraphicsSceneMouseEvent* event ); - virtual bool eventFilter( QObject* obj, QEvent* event ); + GraphicsViewCurveInputBase(QObject* parent, QGraphicsScene* scene); - PointsGraphicsItem pointsGraphicsItem; // shows user specified curve points - bool snappingEnabled; - bool snapToGridEnabled; - QColor color; + void setInputMethod(CurveInputMethod*); +private: + // active input method + CurveInputMethod* inputMethod; }; // class GraphicsViewCurveInputBase -template < typename ArrTraits > -class GraphicsViewCurveInput : public GraphicsViewCurveInputBase { }; - -/** - Specialization of GraphicsViewCurveInput for Arr_segment_traits_2; handles - user-guided generation of line segment curves. -*/ -template < typename Kernel_ > -class GraphicsViewCurveInput< CGAL::Arr_segment_traits_2< Kernel_ > >: - public GraphicsViewCurveInputBase -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_segment_traits_2< Kernel > Traits; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - - GraphicsViewCurveInput( QObject* parent ): - GraphicsViewCurveInputBase( parent ), - second( false ) - { - this->segmentGuide.setZValue( 100 ); - this->setColor( this->color ); - } - - void setColor( QColor c ) - { - this->GraphicsViewCurveInputBase::setColor( c ); - - QPen pen = this->segmentGuide.pen( ); - pen.setColor( this->color ); - this->segmentGuide.setPen( pen ); - } - -protected: - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ) - { - if ( this->second ) - { - Point_2 clickedPoint = this->snapPoint( event ); - Segment_2 segment( this->p1, clickedPoint ); - QLineF qSegment = this->convert( segment ); - this->segmentGuide.setLine( qSegment ); - } - } - - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - if ( !this->second ) - { - this->second = true; - this->p1 = this->snapPoint( event ); - QPointF pt = this->convert( this->p1 ); - this->segmentGuide.setLine( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - if ( this->scene != NULL ) - { - this->scene->addItem( &( this->segmentGuide ) ); - } - this->pointsGraphicsItem.insert( pt ); - } - else - { - this->second = false; - this->p2 = this->snapPoint( event ); - if ( this->scene != NULL ) - { - this->scene->removeItem( &( this->segmentGuide ) ); - } - if ( traits.compare_xy_2_object()( this->p1, this->p2 ) == CGAL::EQUAL ) - { - return; - } - this->pointsGraphicsItem.clear( ); - Curve_2 res( this->p1, this->p2 ); - Q_EMIT generate( CGAL::make_object( res ) ); - } - } - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; - } - - Traits traits; - Converter< Kernel > convert; - Point_2 p1; - Point_2 p2; - bool second; - - QGraphicsLineItem segmentGuide; -}; // class GraphicsViewCurveInput< CGAL::Arr_segment_traits_2< Kernel_ > > - -/** - Specialization of GraphicsViewCurveInput for Arr_polyline_traits_2; handles - user-guided generation of line segment curves. -*/ -template < typename SegmentTraits > -class GraphicsViewCurveInput< CGAL::Arr_polyline_traits_2< SegmentTraits > >: - public GraphicsViewCurveInputBase -{ -public: - typedef CGAL::Arr_polyline_traits_2< SegmentTraits > Traits; - typedef typename Traits::Construct_curve_2 Construct_polyline; - typedef typename Traits::Curve_2 Curve_2; - typedef typename SegmentTraits::Kernel Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - - GraphicsViewCurveInput( QObject* parent ): - GraphicsViewCurveInputBase( parent ) - { } - -protected: - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ) - { - if ( ! this->polylineGuide.empty( ) ) - { - Point_2 clickedPoint = this->snapPoint( event ); - // TODO: make it work for the latest line segment - Segment_2 segment( this->points.back( ), clickedPoint ); - QLineF qSegment = this->convert( segment ); - this->polylineGuide.back( )->setLine( qSegment ); - } - } - - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - // Obtain a functor for the construction of polylines - Traits poly_tr; - Construct_polyline construct_poly = poly_tr.construct_curve_2_object(); - - Point_2 clickedPoint = this->snapPoint( event ); - if ( this->points.empty( ) ) - { // first - // add clicked point to polyline - this->points.push_back( clickedPoint ); - - QPointF pt = this->convert( clickedPoint ); - QGraphicsLineItem* lineItem = - new QGraphicsLineItem( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - lineItem->setZValue( 100 ); - QPen pen = lineItem->pen( ); - pen.setColor( this->color ); - lineItem->setPen( pen ); - this->polylineGuide.push_back( lineItem ); - if ( this->scene != NULL ) - { - this->scene->addItem( this->polylineGuide.back( ) ); - } - } - else - { - // add clicked point to polyline - this->points.push_back( clickedPoint ); - - if ( event->button( ) == ::Qt::RightButton ) - { // finalize polyline input - for ( unsigned int i = 0; i < this->polylineGuide.size( ); ++i ) - { - if ( this->scene != NULL ) - { - this->scene->removeItem( this->polylineGuide[ i ] ); - } - delete this->polylineGuide[ i ]; - } - this->polylineGuide.clear( ); - Curve_2 res = - construct_poly( this->points.begin( ), this->points.end( ) ); - this->points.clear( ); - - Q_EMIT generate( CGAL::make_object( res ) ); - } - else - { // start the next segment - QPointF pt = this->convert( clickedPoint ); - QGraphicsLineItem* lineItem = - new QGraphicsLineItem( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - lineItem->setZValue( 100 ); - QPen pen = lineItem->pen( ); - pen.setColor( this->color ); - lineItem->setPen( pen ); - this->polylineGuide.push_back( lineItem ); - if ( this->scene != NULL ) - { - this->scene->addItem( this->polylineGuide.back( ) ); - } - } - } - } - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; - } - - Converter< Kernel > convert; - std::vector< Point_2 > points; - - std::vector< QGraphicsLineItem* > polylineGuide; -}; - - // class GraphicsViewCurveInput< CGAL::Arr_polyline_traits_2 > - -/** - Specialization of GraphicsViewCurveInput for Arr_conic_traits_2; handles - user-guided generation of conic curves. -*/ -template < typename RatKernel, typename AlgKernel, typename NtTraits > -class GraphicsViewCurveInput< CGAL::Arr_conic_traits_2< - RatKernel, AlgKernel, NtTraits > >: - public GraphicsViewCurveInputBase -{ -public: - typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > Traits; - typedef typename Traits::Curve_2 Curve_2; - // basically, an AlgKernel::Point_2 with metadata - typedef typename Traits::Point_2 Point_2; - typedef AlgKernel Kernel; - // typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename RatKernel::FT Rat_FT; - typedef typename RatKernel::Point_2 Rat_point_2; - typedef typename RatKernel::Segment_2 Rat_segment_2; - typedef typename RatKernel::Circle_2 Rat_circle_2; - typedef enum ConicType { - CONIC_SEGMENT, - CONIC_CIRCLE, - CONIC_ELLIPSE, - CONIC_THREE_POINT, - CONIC_FIVE_POINT - } ConicType; - - /*! Constructor */ - GraphicsViewCurveInput( QObject* parent ) : - GraphicsViewCurveInputBase( parent ), - circleItem( NULL ), - ellipseItem( NULL ), - conicType( CONIC_SEGMENT ) - { } - - void setConicType( ConicType conicType_ ) - { - this->conicType = conicType_; - } - - ConicType getConicType( ) const - { - return this->conicType; - } - -protected: - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ) - { - if ( ! this->polylineGuide.empty( ) ) - { - if ( this->conicType == CONIC_SEGMENT ) - { - - Point_2 clickedPoint = this->snapPoint( event ); - // TODO: make it work for the latest line segment - Segment_2 segment( this->points.back( ), clickedPoint ); - QLineF qSegment = this->convert( segment ); - this->polylineGuide.back( )->setLine( qSegment ); - } - } - if ( this->circleItem != NULL ) - { - QPointF p1 = this->convert( this->points.back( ) ); - QPointF p2 = this->convert( this->snapPoint( event ) ); - double radius = sqrt( (p1.x( ) - p2.x( ))*(p1.x( ) - p2.x( )) - + (p1.y( ) - p2.y( ))*(p1.y( ) - p2.y( )) ); - // double d = radius * sqrt( 2.0 ); - this->circleItem->setRect( p1.x( ) - radius, p1.y( ) - - radius, 2*radius, 2*radius ); - } - if ( this->ellipseItem != NULL ) - { - Point_2 p1 = this->points.back( ); - Point_2 p2 = this->snapPoint( event ); - CGAL::Bbox_2 bb = p1.bbox( ) + p2.bbox( ); - double w = bb.xmax( ) - bb.xmin( ); - double h = bb.ymax( ) - bb.ymin( ); - this->ellipseItem->setRect( bb.xmin( ), bb.ymin( ), w, h ); - } - } - - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->snapPoint( event ); - this->points.push_back( clickedPoint ); - this->pointsGraphicsItem.insert( clickedPoint ); - - if ( this->points.size( ) == 1 ) - { // first - // add clicked point to polyline - - if ( this->conicType == CONIC_SEGMENT ) - { - QPointF pt = this->convert( clickedPoint ); - QGraphicsLineItem* lineItem = - new QGraphicsLineItem( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - lineItem->setZValue( 100 ); - QPen pen = lineItem->pen( ); - pen.setColor( this->color ); - lineItem->setPen( pen ); - this->polylineGuide.push_back( lineItem ); - if ( this->scene != NULL ) - { - this->scene->addItem( this->polylineGuide.back( ) ); - } - } - else if ( this->conicType == CONIC_CIRCLE ) - { - QPointF pt = this->convert( clickedPoint ); - if ( this->scene != NULL ) - { - QGraphicsEllipseItem* ellipse = - this->scene->addEllipse( pt.x( ), pt.y( ), 0, 0 ); - ellipse->setZValue( 100 ); - QPen pen = ellipse->pen( ); - pen.setColor( this->color ); - ellipse->setPen( pen ); - this->circleItem = ellipse; - } - } - else if ( this->conicType == CONIC_ELLIPSE ) - { - QPointF pt = this->convert( clickedPoint ); - if ( this->scene != NULL ) - { - QGraphicsEllipseItem* ellipse = - this->scene->addEllipse( pt.x( ), pt.y( ), 0, 0 ); - ellipse->setZValue( 100 ); - QPen pen = ellipse->pen( ); - pen.setColor( this->color ); - ellipse->setPen( pen ); - this->ellipseItem = ellipse; - } - } - } - else - { - if ( this->conicType == CONIC_SEGMENT ) - { - for ( unsigned int i = 0; i < this->polylineGuide.size( ); ++i ) - { - if ( this->scene != NULL ) - { - this->scene->removeItem( this->polylineGuide[ i ] ); - } - delete this->polylineGuide[ i ]; - } - this->polylineGuide.clear( ); - - double x1 = CGAL::to_double( this->points[ 0 ].x( ) ); - double y1 = CGAL::to_double( this->points[ 0 ].y( ) ); - double x2 = CGAL::to_double( this->points[ 1 ].x( ) ); - double y2 = CGAL::to_double( this->points[ 1 ].y( ) ); - Curve_2 res = Curve_2( Rat_segment_2( Rat_point_2( x1, y1 ), - Rat_point_2( x2, y2 ) ) ); - // std::cout << "res is " << ( (res.is_valid( ))? "" : "not ") - // << "valid" << std::endl; - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - - Q_EMIT generate( CGAL::make_object( res ) ); - } - else if ( this->conicType == CONIC_CIRCLE ) - { - if ( this->scene != NULL ) - { - this->scene->removeItem( this->circleItem ); - } - this->circleItem = NULL; - - // std::cout << "TODO: Add the circle" << std::endl; - double x1 = CGAL::to_double( this->points[ 0 ].x( ) ); - double y1 = CGAL::to_double( this->points[ 0 ].y( ) ); - double x2 = CGAL::to_double( this->points[ 1 ].x( ) ); - double y2 = CGAL::to_double( this->points[ 1 ].y( ) ); - double sq_rad = CGAL::square(x2 - x1) + CGAL::square(y2 - y1); - Curve_2 res = Curve_2( Rat_circle_2( Rat_point_2( x1, y1 ), sq_rad ) ); - - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - Q_EMIT generate( CGAL::make_object( res ) ); - } - else if ( this->conicType == CONIC_ELLIPSE ) - { - if ( this->scene != NULL ) - { - this->scene->removeItem( this->ellipseItem ); - } - this->ellipseItem = NULL; - - CGAL::Bbox_2 bb = this->points[ 0 ].bbox( ) + this->points[ 1 ].bbox( ); - double x1 = CGAL::to_double( bb.xmin( ) ); - double y1 = CGAL::to_double( bb.ymin( ) ); - double x2 = CGAL::to_double( bb.xmax( ) ); - double y2 = CGAL::to_double( bb.ymax( ) ); - // double sq_rad = CGAL::square(x2 - x1) + CGAL::square(y2 - y1); - - Rat_FT a = CORE::abs( Rat_FT(x1) - Rat_FT(x2) )/2; - Rat_FT b = CORE::abs( Rat_FT(y1) - Rat_FT(y2) )/2; - Rat_FT a_sq = a*a; - Rat_FT b_sq = b*b; - Rat_FT x0 = (x2 + x1)/2; - Rat_FT y0 = (y2 + y1)/2; - - Rat_FT r = b_sq; - Rat_FT s = a_sq; - Rat_FT t = 0; - Rat_FT u = -2*x0*b_sq; - Rat_FT v = -2*y0*a_sq; - Rat_FT ww = x0*x0*b_sq + y0*y0*a_sq - a_sq*b_sq; - - Curve_2 res = Curve_2( r, s, t, u, v, ww ); - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - Q_EMIT generate( CGAL::make_object( res ) ); - } - else if ( this->conicType == CONIC_THREE_POINT ) - { - if ( this->points.size( ) == 3 ) - { - QPointF qp1 = this->convert( this->points[ 0 ] ); - QPointF qp2 = this->convert( this->points[ 1 ] ); - QPointF qp3 = this->convert( this->points[ 2 ] ); - Rat_point_2 p1 = Rat_point_2( qp1.x( ), qp1.y( ) ); - Rat_point_2 p2 = Rat_point_2( qp2.x( ), qp2.y( ) ); - Rat_point_2 p3 = Rat_point_2( qp3.x( ), qp3.y( ) ); - RatKernel ker; - if ( ! ker.collinear_2_object()( p1, p2, p3 ) ) - { - Curve_2 res( p1, p2, p3 ); - Q_EMIT generate( CGAL::make_object( res ) ); - } - else - { - std::cout << "Points don't specify a valid conic." - << " Try again!" << std::endl; - } - - // TODO: make a valid curve and insert it - - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - } - } - else if ( this->conicType == CONIC_FIVE_POINT ) - { - if ( this->points.size( ) == 5 ) - { - QPointF qp1 = this->convert( this->points[ 0 ] ); - QPointF qp2 = this->convert( this->points[ 1 ] ); - QPointF qp3 = this->convert( this->points[ 2 ] ); - QPointF qp4 = this->convert( this->points[ 3 ] ); - QPointF qp5 = this->convert( this->points[ 4 ] ); - Rat_point_2 p1 = Rat_point_2( qp1.x( ), qp1.y( ) ); - Rat_point_2 p2 = Rat_point_2( qp2.x( ), qp2.y( ) ); - Rat_point_2 p3 = Rat_point_2( qp3.x( ), qp3.y( ) ); - Rat_point_2 p4 = Rat_point_2( qp4.x( ), qp4.y( ) ); - Rat_point_2 p5 = Rat_point_2( qp5.x( ), qp5.y( ) ); - try - { - Curve_2 res( p1, p2, p3, p4, p5 ); - if ( res.is_valid( ) ) - { - Q_EMIT generate( CGAL::make_object( res ) ); - } - else - { - std::cout << "Points don't specify a valid conic. Try again!" - << std::endl; - } - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - - } - catch (...) - { - std::cout << "Points don't specify a valid conic. Try again!" - << std::endl; - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - } - } - } - } - } - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; - } - - Converter< Kernel > convert; - std::vector< Point_2 > points; - std::vector< QGraphicsLineItem* > polylineGuide; - QGraphicsEllipseItem* circleItem; - QGraphicsEllipseItem* ellipseItem; - - Traits traits; - ConicType conicType; -}; - -// class GraphicsViewCurveInput< CGAL::Arr_conic_traits_2< -// RatKernel, AlgKernel, NtTraits > > - -/** - Specialization of GraphicsViewCurveInput for Arr_linear_traits_2; handles - user-guided generation of line segment curves. -*/ -template < typename Kernel_ > -class GraphicsViewCurveInput< CGAL::Arr_linear_traits_2< Kernel_ > >: - public GraphicsViewCurveInputBase -{ -public: // typedefs - typedef Kernel_ Kernel; - typedef GraphicsViewCurveInputBase Superclass; - typedef CGAL::Arr_linear_traits_2< Kernel > Traits; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Kernel::Line_2 Line_2; - enum CurveType - { - SEGMENT, RAY, LINE - }; - -public: // constructors - GraphicsViewCurveInput( QObject* parent ): - GraphicsViewCurveInputBase( parent ), - second( false ), - curveType( SEGMENT ) - { - this->setColor( this->color ); - } - -public: // methods - void setCurveType( CurveType type ) - { - this->curveType = type; - } - - void setColor( QColor c ) - { - this->GraphicsViewCurveInputBase::setColor( c ); - QPen pen = this->segmentGuide.pen( ); - pen.setColor( c ); - this->segmentGuide.setPen( pen ); - } - -protected: // methods - virtual bool eventFilter( QObject* obj, QEvent* event ) - { - // before we do anything, update the clipping rect - // TODO: somehow only update this when the view changes - QRectF clippingRect = this->viewportRect( ); - if ( !clippingRect.isValid( ) ) - { - //std::cout << "Warning: invalid clipping rect" << std::endl; - } - this->convert = Converter< Kernel >( clippingRect ); - - // now handle the event - return Superclass::eventFilter( obj, event ); - } - - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ) - { - if ( this->second ) - { - Point_2 hoverPoint = this->snapPoint( event ); - if ( p1 == hoverPoint ) - return; - QLineF qSegment; - if ( this->curveType == SEGMENT ) - { - Segment_2 segment( this->p1, hoverPoint ); - qSegment = this->convert( segment ); - } - else if ( this->curveType == RAY ) - { - Ray_2 ray( this->p1, hoverPoint ); - qSegment = this->convert( ray ); - } - else // this->curveType == LINE - { - Line_2 line( this->p1, hoverPoint ); - qSegment = this->convert( line ); - } - this->segmentGuide.setLine( qSegment ); - } - } - - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - if ( !this->second ) - { // fix our first point - this->second = true; - this->p1 = this->snapPoint( event ); - QPointF pt = this->convert( this->p1 ); - this->segmentGuide.setLine( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - if ( this->scene != NULL ) - { - this->scene->addItem( &( this->segmentGuide ) ); - } - } - else // this->second == true - { - this->second = false; - this->p2 = this->snapPoint( event ); - - // skip if degenerate - if ( this->p1 == this->p2 ) - return; - - if ( this->scene != NULL ) - { - this->scene->removeItem( &( this->segmentGuide ) ); - } - - Curve_2 res; - if ( this->curveType == SEGMENT ) - { - res = Curve_2( Segment_2( this->p1, this->p2 ) ); - } - else if ( this->curveType == RAY ) - { - res = Curve_2( Ray_2( this->p1, this->p2 ) ); - } - else // this->curveType == LINE - { - res = Curve_2( Line_2( this->p1, this->p2 ) ); - } - - Q_EMIT generate( CGAL::make_object( res ) ); - } - } - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; - } - -protected: // fields - Converter< Kernel > convert; - Point_2 p1; - Point_2 p2; - bool second; - - QGraphicsLineItem segmentGuide; - CurveType curveType; -}; // class GraphicsViewCurveInput< CGAL::Arr_linear_traits_2< Kernel_ > > - -/** - Specialization of GraphicsViewCurveInput for Arr_circular_arc_traits_2; handles - user-guided generation of circular arc curves. -*/ -template < typename CircularKernel > -class GraphicsViewCurveInput > : - public GraphicsViewCurveInputBase -{ -public: - typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > Traits; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::Point_2 Point_2; - typedef Point_2 Arc_point_2; - typedef typename CircularKernel::Point_2 Non_arc_point_2; - typedef typename CircularKernel::Circle_2 Circle_2; - typedef typename CircularKernel::Circular_arc_2 Circular_arc_2; - typedef CircularKernel Kernel; - - GraphicsViewCurveInput( QObject* parent ): - GraphicsViewCurveInputBase( parent ) - { } - -protected: - void mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) {} - - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->snapPoint( event ); - this->points.push_back( clickedPoint ); - this->pointsGraphicsItem.insert( clickedPoint ); - - if ( this->points.size( ) == 3 ) - { - Arc_point_2 p1 = this->points[ 0 ]; - Arc_point_2 p2 = this->points[ 1 ]; - Arc_point_2 p3 = this->points[ 2 ]; - Non_arc_point_2 pp1( CGAL::to_double(p1.x( )), CGAL::to_double(p1.y()) ); - Non_arc_point_2 pp2( CGAL::to_double(p2.x( )), CGAL::to_double(p2.y()) ); - Non_arc_point_2 pp3( CGAL::to_double(p3.x( )), CGAL::to_double(p3.y()) ); - Kernel ker; - if ( ! ker.collinear_2_object()( pp1, pp2, pp3 ) ) - { - Circle_2 circle( pp1, pp2, pp3 ); - Circular_arc_2 arc( circle, pp1, pp3 ); - //Circular_arc_2 arc2( circle, pp1, pp3 ); - std::vector< CGAL::Object > subarcs; - CGAL::make_x_monotone( arc, std::back_inserter( subarcs ) ); - typename CircularKernel::Has_on_2 has_on; - bool isOn = false; - for ( unsigned int i = 0; i < subarcs.size( ); ++i ) - { - Circular_arc_2 subarc; - if ( CGAL::assign( subarc, subarcs[ i ] ) ) - { - if ( has_on( subarc, pp2 ) ) - { - isOn = true; - break; - } - } - } - - if ( isOn ) - { - Curve_2 res( circle, pp1, pp3 ); - // std::cout << res << std::endl; - Q_EMIT generate( CGAL::make_object( res ) ); - } - else - { - Curve_2 res( circle, pp3, pp1 ); - // std::cout << res << std::endl; - Q_EMIT generate( CGAL::make_object( res ) ); - } - } - else - { - std::cout << "Points don't specify a valid circular arc." - << " Try again!" << std::endl; - } - - this->points.clear( ); - this->pointsGraphicsItem.clear( ); - } - } - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; - } - - Converter< Kernel > convert; - std::vector< Point_2 > points; -}; // class GraphicsViewCurveInput< CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > > - -#if 0 -template < typename Coefficient_ > -class GraphicsViewCurveInput > : - public GraphicsViewCurveInputBase -{ - typedef Coefficient_ Coefficent; - typedef CGAL::Arr_algebraic_segment_traits_2 - Traits; - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef Traits::Point_2 Point_2; - typedef Kernel::Point_2 Kernel_point_2; - typedef Kernel::Segment_2 Segment_2; - -public: - GraphicsViewCurveInput( QObject* parent ): - GraphicsViewCurveInputBase( parent ), - second( false ) - { } - -public: - void mousePressEvent( QGraphicsSceneMouseEvent* event ) - { - if ( ! this->second ) - { - this->second = true; - this->p1 = this->snapPoint( event ); - QPointF pt = event->scenePos( ); - this->segmentGuide.setLine( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - if ( this->scene != NULL ) - { - this->scene->addItem( &( this->segmentGuide ) ); - } - } - else - { - this->second = false; - Point_2 p2 = this->snapPoint( event ); - if ( this->scene != NULL ) - { - this->scene->removeItem( &( this->segmentGuide ) ); - } - if ( traits.compare_xy_2_object()( this->p1, p2 ) == CGAL::EQUAL ) - { - return; - } - // std::cout << "Algebraic traits curve insert stub" << std::endl; - } - } - - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ) - { - if ( this->second ) - { - Kernel_point_2 clickedPoint = this->convert( event->scenePos( ) ); - std::pair< double, double > pp1 = this->p1.to_double( ); - QPointF qp1( pp1.first, pp1.second ); - Kernel_point_2 firstPoint = this->convert( qp1 ); - Segment_2 segment( firstPoint, clickedPoint ); - QLineF qSegment = this->convert( segment ); - this->segmentGuide.setLine( qSegment ); - } - } - - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Kernel_point_2 pt = this->convert( event->scenePos( ) ); - Point_2 res = this->toArrPoint( pt ); - return res; - } - -protected: - Traits traits; - Converter< Kernel > convert; - Arr_construct_point_2< Traits > toArrPoint; - Point_2 p1; - bool second; - QGraphicsLineItem segmentGuide; -}; -#endif - } // namespace Qt } // namespace CGAL +// TODO: Find a better place for these functions +// (away from ArrangementDemoWindow.cpp, for better compilation speeds) +#ifdef CGAL_USE_CORE +CGAL::Object algebraicCurveFromExpression( + const CGAL::Object& arr, const std::string&, bool& is_first_curve); +CGAL::Object rationalCurveFromExpression( + const CGAL::Object& arr, const std::string&, const std::string&, + bool& is_first_curve); +#endif + #endif // CGAL_QT_GRAPHICS_VIEW_SEGMENT_INPUT_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h new file mode 100644 index 00000000000..1c8a1b94699 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewCurveInputTyped.h @@ -0,0 +1,281 @@ +// Copyright (c) 2008, 2012, 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef CGAL_QT_GRAPHICS_VIEW_CURVE_INPUT_TYPED_H +#define CGAL_QT_GRAPHICS_VIEW_CURVE_INPUT_TYPED_H + +#include +#include +#include +#include +#include + +#include "Callback.h" +#include "CurveInputMethods.h" +#include "ForwardDeclarations.h" +#include "GraphicsSceneMixin.h" +#include "GraphicsViewCurveInput.h" +#include "PointSnapper.h" + +class QEvent; + +namespace demo_types +{ +enum class TraitsType : int; +} + +namespace CGAL +{ +namespace Qt +{ + +template +class CurveGeneratorBase +{ +public: + using ArrTraits = ArrTraits_; + using Curve_2 = typename ArrTraits::Curve_2; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + + void setTraits(const ArrTraits* traits_); + + boost::optional + generate(const std::vector& clickedPoints, CurveType type); + + virtual boost::optional + generateSegment(const std::vector&) { return {}; } + virtual boost::optional + generateRay(const std::vector&) { return {}; } + virtual boost::optional + generateLine(const std::vector&) { return {}; } + virtual boost::optional + generatePolyline(const std::vector&) { return {}; } + virtual boost::optional + generateCircle(const std::vector&) { return {}; } + virtual boost::optional + generateEllipse(const std::vector&) { return {}; } + virtual boost::optional + generateThreePointCircularArc(const std::vector&) { return {}; } + virtual boost::optional + generateFivePointConicArc(const std::vector&) { return {}; } + virtual boost::optional + generateBezier(const std::vector&) { return {}; } + + const ArrTraits* traits; +}; + +template +struct CurveGenerator : public CurveGeneratorBase +{ +}; + +template +struct CurveGenerator> : + public CurveGeneratorBase> +{ + using ArrTraits = CGAL::Arr_segment_traits_2; + using Curve_2 = typename ArrTraits::Curve_2; + using Kernel = Kernel_; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + + boost::optional + generateSegment(const std::vector&) override; +}; + +template +struct CurveGenerator> : + public CurveGeneratorBase> +{ + using ArrTraits = CGAL::Arr_polyline_traits_2; + using Curve_2 = typename ArrTraits::Curve_2; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + + boost::optional + generatePolyline(const std::vector&) override; +}; + +template +struct CurveGenerator> : + public CurveGeneratorBase< + Arr_conic_traits_2> +{ + using ArrTraits = Arr_conic_traits_2; + using Curve_2 = typename ArrTraits::Curve_2; + using Kernel = AlgKernel; + using Segment_2 = typename Kernel::Segment_2; + using Rat_FT = typename RatKernel::FT; + using Rat_point_2 = typename RatKernel::Point_2; + using Rat_segment_2 = typename RatKernel::Segment_2; + using Rat_circle_2 = typename RatKernel::Circle_2; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + + boost::optional + generateSegment(const std::vector&) override; + boost::optional generateCircle(const std::vector&) override; + boost::optional + generateEllipse(const std::vector&) override; + boost::optional + generateThreePointCircularArc(const std::vector&) override; + boost::optional + generateFivePointConicArc(const std::vector&) override; +}; + +template +struct CurveGenerator> : + public CurveGeneratorBase> +{ + using Kernel = Kernel_; + using KernelPoint = typename Kernel::Point_2; + using ArrTraits = CGAL::Arr_linear_traits_2; + using Curve_2 = typename ArrTraits::Curve_2; + using Segment_2 = typename Kernel::Segment_2; + using Ray_2 = typename Kernel::Ray_2; + using Line_2 = typename Kernel::Line_2; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + + boost::optional + generateSegment(const std::vector&) override; + boost::optional generateRay(const std::vector&) override; + boost::optional generateLine(const std::vector&) override; +}; + +template +struct CurveGenerator> : + public CurveGeneratorBase< + CGAL::Arr_algebraic_segment_traits_2> +{ + using Coefficient = Coefficient_; + using ArrTraits = CGAL::Arr_algebraic_segment_traits_2; + using X_monotone_curve_2 = typename ArrTraits::X_monotone_curve_2; + using Polynomial_2 = typename ArrTraits::Polynomial_2; + using Curve_2 = typename ArrTraits::Curve_2; + using Algebraic_real_1 = typename ArrTraits::Algebraic_real_1; + using Rational = typename Algebraic_real_1::Rational; + using RationalTraits = Rational_traits; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + + boost::optional generateLine(const std::vector&) override; + boost::optional generateCircle(const std::vector&) override; + boost::optional + generateEllipse(const std::vector&) override; + +private: + boost::optional generateEllipse_(const Point_2&, Rational, Rational); +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +struct CurveGenerator< + Arr_Bezier_curve_traits_2> : + public CurveGeneratorBase< + Arr_Bezier_curve_traits_2> +{ + using ArrTraits = + Arr_Bezier_curve_traits_2; + using Super = CurveGeneratorBase; + using Point_2 = typename Super::Point_2; + using Curve_2 = typename ArrTraits::Curve_2; + + boost::optional generateBezier(const std::vector&) override; +}; + +template +struct GraphicsViewCurveInputTypeHelper +{ + using InputMethodTuple = std::tuple<>; +}; + +template +struct GraphicsViewCurveInputTypeHelper> +{ + using InputMethodTuple = std::tuple; +}; + +template +struct GraphicsViewCurveInputTypeHelper< + CGAL::Arr_polyline_traits_2> +{ + using InputMethodTuple = std::tuple; +}; + +template +struct GraphicsViewCurveInputTypeHelper> +{ + using InputMethodTuple = + std::tuple; +}; + +template +struct GraphicsViewCurveInputTypeHelper< + CGAL::Arr_conic_traits_2> +{ + using InputMethodTuple = std::tuple< + SegmentInputMethod, CircleInputMethod, EllipseInputMethod, + ThreePointCircularInputMethod, FivePointConicInputMethod>; +}; + +template +struct GraphicsViewCurveInputTypeHelper< + CGAL::Arr_algebraic_segment_traits_2> +{ + using InputMethodTuple = + std::tuple; +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +struct GraphicsViewCurveInputTypeHelper> +{ + using InputMethodTuple = std::tuple; +}; + +template +class GraphicsViewCurveInput : + public GraphicsViewCurveInputBase, + public CurveInputMethodCallback +{ + using Self = GraphicsViewCurveInput; + using Arrangement = Arr_; + using ArrTraits = typename Arrangement::Geometry_traits_2; + using Curve_2 = typename Arrangement::Curve_2; + using InputMethodTuple = + typename GraphicsViewCurveInputTypeHelper::InputMethodTuple; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + +public: + GraphicsViewCurveInput( + Arrangement* arrangement_, QObject* parent, QGraphicsScene* scene); + void setCurveType(CurveType type) override; + void setPointSnapper(PointSnapperBase*) override; + void generate(CGAL::Object o) override; + void curveInputDoneEvent( + const std::vector& clickedPoints, CurveType type) override; + +private: + template + void setDefaultInputMethod(std::true_type); + void setDefaultInputMethod(std::false_type); + + Arrangement* arrangement; + InputMethodTuple inputMethods; + CurveGenerator curveGenerator; +}; + +} // namespace Qt +} // namespace CGAL + +#endif // CGAL_QT_GRAPHICS_VIEW_SEGMENT_INPUT_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.cpp deleted file mode 100644 index b85ee390c6a..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#include "GraphicsViewSegmentInput.h" - -#include -#include - -namespace CGAL { -namespace Qt { - -GraphicsViewSegmentInputBase:: -GraphicsViewSegmentInputBase( QObject* parent ): - GraphicsViewInput( parent ), - scene( NULL ), - snappingEnabled( false ), - snapToGridEnabled( false ) -{ } - -void GraphicsViewSegmentInputBase::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; -} - -QGraphicsScene* GraphicsViewSegmentInputBase::getScene( ) const -{ - return this->scene; -} - -void GraphicsViewSegmentInputBase:: -mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) -{ } - -void GraphicsViewSegmentInputBase:: -mousePressEvent(QGraphicsSceneMouseEvent* /* event */) -{ - // std::cout << "GraphicsViewSegmentInputBase::mousePressEvent" << std::endl; -} - -bool GraphicsViewSegmentInputBase::eventFilter( QObject* obj, QEvent* event ) -{ - if ( event->type( ) == QEvent::GraphicsSceneMouseMove ) - { - QGraphicsSceneMouseEvent* mouseEvent = - static_cast< QGraphicsSceneMouseEvent* >( event ); - this->mouseMoveEvent( mouseEvent ); - } - else if ( event->type( ) == QEvent::GraphicsSceneMousePress ) - { - QGraphicsSceneMouseEvent* mouseEvent = - static_cast< QGraphicsSceneMouseEvent* >( event ); - this->mousePressEvent( mouseEvent ); - } - - return QObject::eventFilter( obj, event ); -} - -void GraphicsViewSegmentInputBase::setSnappingEnabled( bool b ) -{ - this->snappingEnabled = b; -} - -void GraphicsViewSegmentInputBase::setSnapToGridEnabled( bool b ) -{ - this->snapToGridEnabled = b; -} - -QRectF GraphicsViewSegmentInputBase::viewportRect( ) const -{ - QRectF res; - if ( this->scene == NULL ) - { - return res; - } - - QList< QGraphicsView* > views = this->scene->views( ); - if ( views.size( ) == 0 ) - { - return res; - } - // assumes the first view is the right one - QGraphicsView* viewport = views.first( ); - QPointF p1 = viewport->mapToScene( 0, 0 ); - QPointF p2 = viewport->mapToScene( viewport->width( ), viewport->height( ) ); - res = QRectF( p1, p2 ); - - return res; -} - -} // namespace Qt -} // namespace CGAL diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.h deleted file mode 100644 index d1d5b3ed921..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GraphicsViewSegmentInput.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef CGAL_QT_GRAPHICS_VIEW_SEGMENT_INPUT_H -#define CGAL_QT_GRAPHICS_VIEW_SEGMENT_INPUT_H - -#include -#include -#include -#include -#include -//#include -//#include "Callback.h" -#include "ISnappable.h" - -namespace CGAL { -namespace Qt { - -class GraphicsViewSegmentInputBase : - public GraphicsViewInput, public ISnappable -{ -public: - virtual void setScene( QGraphicsScene* scene_ ); - QGraphicsScene* getScene( ) const; - - void setSnappingEnabled( bool b ); - void setSnapToGridEnabled( bool b ); - -protected: - GraphicsViewSegmentInputBase( QObject* parent_ ); - virtual void mouseMoveEvent( QGraphicsSceneMouseEvent* event ); - virtual void mousePressEvent( QGraphicsSceneMouseEvent* event ); - virtual bool eventFilter( QObject* obj, QEvent* event ); - - QRectF viewportRect( ) const; - - QGraphicsScene* scene; - bool snappingEnabled; - bool snapToGridEnabled; - -}; // class GraphicsViewSegmentInputBase - -template < class K_ > -class GraphicsViewSegmentInput: public GraphicsViewSegmentInputBase -{ -public: - typedef K_ Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - - GraphicsViewSegmentInput( QObject* parent ); - -protected: - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ); - void mousePressEvent( QGraphicsSceneMouseEvent* event ); - - // override this to snap to the points you like - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ); - - Converter< Kernel > convert; - Point_2 p1; - Point_2 p2; - bool second; - - QGraphicsLineItem segmentGuide; -}; // class GraphicsViewSegmentInput - - -template < class K_ > -GraphicsViewSegmentInput< K_ >::GraphicsViewSegmentInput( QObject* parent ): - GraphicsViewSegmentInputBase( parent ), - second( false ) -{ } - -template < class K_ > -typename GraphicsViewSegmentInput< K_ >::Point_2 -GraphicsViewSegmentInput< K_ >::snapPoint( QGraphicsSceneMouseEvent* event ) -{ - Point_2 clickedPoint = this->convert( event->scenePos( ) ); - return clickedPoint; -} - -template < class K_ > -void -GraphicsViewSegmentInput< K_ >::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - if ( this->second ) - { - Point_2 clickedPoint = this->snapPoint( event ); - Segment_2 segment( this->p1, clickedPoint ); - QLineF qSegment = this->convert( segment ); - segmentGuide.setLine( qSegment ); - } -} - -template < class K_ > -void -GraphicsViewSegmentInput::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - if ( !this->second ) - { - this->second = true; - this->p1 = this->snapPoint( event ); - QPointF pt = this->convert( this->p1 ); - segmentGuide.setLine( pt.x( ), pt.y( ), pt.x( ), pt.y( ) ); - if ( this->scene != NULL ) - { - this->scene->addItem( &(segmentGuide ) ); - } - } - else - { - this->second = false; - this->p2 = this->snapPoint( event ); - if ( this->scene != NULL ) - { - this->scene->removeItem( &(segmentGuide ) ); - } - Segment_2 res( this->p1, this->p2 ); - Q_EMIT generate( CGAL::make_object( res ) ); - } -} - -} // namespace Qt -} // namespace CGAL - -#endif // CGAL_QT_GRAPHICS_VIEW_SEGMENT_INPUT_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.cpp new file mode 100644 index 00000000000..535f4684975 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.cpp @@ -0,0 +1,237 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "GridGraphicsItem.h" +#include +#include + +#include +#include +#include + +GridGraphicsItem::GridGraphicsItem() : + gridColor{::Qt::gray}, axesColor{::Qt::black}, + labelsColor{::Qt::black}, spacing{75} +{ +} + +int GridGraphicsItem::getXPower5() const { return x_power5; } + +int GridGraphicsItem::getXPower2() const { return x_power2; } + +int GridGraphicsItem::getYPower5() const { return y_power5; } + +int GridGraphicsItem::getYPower2() const { return y_power2; } + +float GridGraphicsItem::getXUnit() const { return x_unit; } + +float GridGraphicsItem::getYUnit() const { return y_unit; } + +QColor GridGraphicsItem::getGridColor() const { return this->gridColor; } + +QColor GridGraphicsItem::getAxesColor() const { return this->axesColor; } + +QColor GridGraphicsItem::getLabelsColor() const { return this->labelsColor; } + +int GridGraphicsItem::getSpacing() const { return this->spacing; } + +void GridGraphicsItem::setGridColor(const QColor& color) +{ + this->gridColor = color; +} + +void GridGraphicsItem::setAxesColor(const QColor& color) +{ + this->axesColor = color; +} + +void GridGraphicsItem::setLabelsColor(const QColor& color) +{ + this->labelsColor = color; +} + +void GridGraphicsItem::setSpacing(int spacing_) +{ + this->spacing = spacing_; + this->update(); +} + +static inline qreal +horizontalAdvance(const QFontMetrics& fm, const QString& text) +{ +#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)) + return fm.horizontalAdvance(text); +#else + return fm.boundingRect(text).width(); +#endif +} + +void GridGraphicsItem::paint( + QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) +{ + // equivalent to m11() and m22() when there are no rotations + QTransform worldTransform = painter->transform(); + QLineF ux_line = worldTransform.map(QLineF{0, 0, 1, 0}); + QLineF uy_line = worldTransform.map(QLineF{0, 0, 0, 1}); + float scaleX = ux_line.length(); + float scaleY = uy_line.length(); + + float gridSceneMaxXLen = spacing / scaleX; + float gridSceneMaxYLen = spacing / scaleY; + + // 2^power2 * 5^power5 = gridSceneMaxSize + x_power5 = std::log(gridSceneMaxXLen) / std::log(5.); + float pow5l = std::pow(5, x_power5); + x_power2 = std::log(gridSceneMaxXLen / pow5l) / std::log(2.); + float pow2l = std::pow(2, x_power2); + + x_unit = pow2l * pow5l; + + y_power5 = std::log(gridSceneMaxYLen) / std::log(5.); + y_power2 = std::log(gridSceneMaxYLen / pow5l) / std::log(2.); + pow5l = std::pow(5, y_power5); + pow2l = std::pow(2, y_power2); + + y_unit = pow2l * pow5l; + + QRectF sceneViewport = this->viewportRect(painter); + + QVarLengthArray linesX; + QVarLengthArray linesY; + + qreal left = int(sceneViewport.left() / x_unit) * x_unit; + qreal top = int(sceneViewport.top() / y_unit) * y_unit; + + for (qreal x = left; x < sceneViewport.right(); x += x_unit) + linesX.append(QLineF(x, sceneViewport.top(), x, sceneViewport.bottom())); + + for (qreal y = top; y < sceneViewport.bottom(); y += y_unit) + linesY.append(QLineF(sceneViewport.left(), y, sceneViewport.right(), y)); + + // set up the painter + QPen gridPen; + gridPen.setColor(this->gridColor); + gridPen.setCosmetic(true); + painter->setPen(gridPen); + + // draw the grid + painter->drawLines(linesX.data(), linesX.size()); + painter->drawLines(linesY.data(), linesY.size()); + + // draw x and y axis + QPen axisPen{this->axesColor}; + axisPen.setCosmetic(true); + painter->setPen(axisPen); + + const double marginX = 15 / scaleX; + const double marginY = 15 / scaleY; + + double xAxis_y = 0; + double yAxis_x = 0; + bool xAxisTop = false; + bool yAxisLeft = false; + + if (sceneViewport.left() > -marginX) + { + yAxis_x = sceneViewport.left() + marginX; + yAxisLeft = true; + } + else if (sceneViewport.right() < marginX) + { + yAxis_x = sceneViewport.right() - marginX; + } + + if (sceneViewport.top() > -marginY) + { + xAxis_y = sceneViewport.top() + marginY; + xAxisTop = true; + } + else if (sceneViewport.bottom() < marginY) + { + xAxis_y = sceneViewport.bottom() - marginY; + } + + painter->drawLine( + QLineF{sceneViewport.left(), xAxis_y, sceneViewport.right(), xAxis_y}); + painter->drawLine( + QLineF{yAxis_x, sceneViewport.bottom(), yAxis_x, sceneViewport.top()}); + + for (qreal x = left; x < sceneViewport.right(); x += x_unit) + painter->drawLine(QLineF(x, xAxis_y - 5 / scaleY, x, xAxis_y + 5 / scaleY)); + + for (qreal y = top; y < sceneViewport.bottom(); y += y_unit) + painter->drawLine(QLineF(yAxis_x - 5 / scaleX, y, yAxis_x + 5 / scaleX, y)); + + QPen labelsPen{this->labelsColor}; + axisPen.setCosmetic(true); + painter->setPen(labelsPen); + + painter->resetTransform(); + + auto&& font = painter->font(); + QFontMetrics fm(font); + qreal txtHeight = fm.height(); + + QPointF uy = {uy_line.dx(), uy_line.dy()}; + float sign = 1; + if (!xAxisTop) sign = -1; + for (qreal x = left; x < sceneViewport.right(); x += x_unit) + { + if (std::abs(x) < x_unit / 2) continue; + QString txt = QString{"%1"}.arg(x); + qreal txtWidth = horizontalAdvance(fm, txt) + 4; + QPointF pos = + worldTransform.map(QPointF{x, xAxis_y}) + + sign * QPointF{uy.x() * txtWidth, uy.y() * txtHeight} / scaleY; + + painter->drawText( + pos.x() - txtWidth / 2, pos.y() - txtHeight / 2, txtWidth, txtHeight, + Qt::AlignHCenter | Qt::AlignVCenter, txt); + } + + QPointF ux = {ux_line.dx(), ux_line.dy()}; + sign = 1; + if (!yAxisLeft) sign = -1; + for (qreal y = top; y < sceneViewport.bottom(); y += y_unit) + { + if (std::abs(y) < y_unit / 2) continue; + QString txt = QString{"%1"}.arg(y); + qreal txtWidth = horizontalAdvance(fm, txt) + 4; + QPointF pos = + worldTransform.map(QPointF{yAxis_x, y}) + + sign * QPointF{ux.x() * txtWidth, ux.y() * txtHeight} / scaleX; + + painter->drawText( + pos.x() - txtWidth / 2, pos.y() - txtHeight / 2, txtWidth, txtHeight, + Qt::AlignHCenter | Qt::AlignVCenter, txt); + } + + // revert the painter + painter->setTransform(worldTransform); +} + +QRectF GridGraphicsItem::boundingRect() const { return this->viewportRect(); } + +QRectF GridGraphicsItem::viewportRect(QPainter* painter) const +{ + QRectF pixelViewport = painter->viewport(); + return painter->transform().inverted().mapRect(pixelViewport); +} + +QRectF GridGraphicsItem::viewportRect() const +{ + QList views = this->scene()->views(); + if (views.size() == 0) return {}; + // assumes the first view is the right one + QGraphicsView* view = views.first(); + return view->mapToScene(QRect{0, 0, view->width(), view->height()}) + .boundingRect(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.h new file mode 100644 index 00000000000..12b82a06990 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/GridGraphicsItem.h @@ -0,0 +1,63 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_GRID_GRAPHICS_ITEM_H +#define ARRANGEMENT_DEMO_GRID_GRAPHICS_ITEM_H + +#include +#include + +class QWidget; +class QPainter; +class QStyleOptionGraphicsItem; + +class GridGraphicsItem : public QGraphicsItem +{ +public: + GridGraphicsItem(); + int getXPower5() const; + int getXPower2() const; + int getYPower5() const; + int getYPower2() const; + float getXUnit() const; + float getYUnit() const; + + QColor getGridColor() const; + QColor getAxesColor() const; + QColor getLabelsColor() const; + int getSpacing() const; + + void setGridColor(const QColor&); + void setAxesColor(const QColor&); + void setLabelsColor(const QColor&); + void setSpacing(int); + +protected: + void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override; + QRectF viewportRect(QPainter*) const; + QRectF viewportRect() const; + QRectF boundingRect() const override; + +private: + QColor gridColor; + QColor axesColor; + QColor labelsColor; + + int spacing; + int x_power5; + int x_power2; + int y_power5; + int y_power2; + float x_unit; + float y_unit; +}; + +#endif // ARRANGEMENT_DEMO_GRID_GRAPHICS_ITEM_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ISnappable.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ISnappable.h deleted file mode 100644 index 47b4da0bcf7..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/ISnappable.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef ISNAPPABLE_H -#define ISNAPPABLE_H - -class ISnappable -{ -public: - virtual ~ISnappable( ) { } - virtual void setSnappingEnabled( bool b ) = 0; - virtual void setSnapToGridEnabled( bool b ) = 0; -}; // class ISnappable - - -#endif // SNAPPABLE_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp new file mode 100644 index 00000000000..45651705ba2 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.cpp @@ -0,0 +1,257 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include "MergeEdgeCallback.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveGraphicsItem.h" +#include "Utils/SplitAndMerge.h" +#include "Utils/Utils.h" + +#include +#include + +template +class MergeEdgeCallback : public MergeEdgeCallbackBase +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Halfedge_handle Halfedge_handle; + typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; + typedef typename Arrangement::Vertex_iterator Vertex_iterator; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + MergeEdgeCallback(Arrangement* arr_, QObject* parent_); + void setScene(QGraphicsScene* scene_) override; + void reset() override; + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + Halfedge_handle getNearestMergeableCurve(QGraphicsSceneMouseEvent* event); + Halfedge_handle + getNearestMergeableCurve(Halfedge_handle h, QGraphicsSceneMouseEvent* event); + + CGAL::Qt::CurveGraphicsItem* highlightedCurve; + CGAL::Qt::CurveGraphicsItem* highlightedCurve2; + Arrangement* arr; + Merge_edge mergeEdge; + Halfedge_handle mergeableHalfedge; + bool isFirst; +}; // class MergeEdgeCallback + +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new MergeEdgeCallback(arr, parent); + } + + MergeEdgeCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +MergeEdgeCallbackBase* MergeEdgeCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + MergeEdgeCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +/*! Constructor */ +template +MergeEdgeCallback::MergeEdgeCallback( + Arrangement* arr_, QObject* parent_) : + MergeEdgeCallbackBase(parent_), + highlightedCurve(new CGAL::Qt::CurveGraphicsItem()), + highlightedCurve2(new CGAL::Qt::CurveGraphicsItem()), arr(arr_), + isFirst(true) +{ + QObject::connect( + this, SIGNAL(modelChanged()), this->highlightedCurve, SLOT(modelChanged())); + QObject::connect( + this, SIGNAL(modelChanged()), this->highlightedCurve2, + SLOT(modelChanged())); +} + +template +void MergeEdgeCallback::setScene(QGraphicsScene* scene_) +{ + Callback::setScene(scene_); + this->highlightedCurve->setScene(scene_); + this->highlightedCurve2->setScene(scene_); + + if (scene_) + { + this->scene->addItem(this->highlightedCurve); + this->scene->addItem(this->highlightedCurve2); + } +} + +template +void MergeEdgeCallback::reset() +{ + this->isFirst = true; + this->highlightedCurve->clear(); + this->highlightedCurve2->clear(); + this->mergeableHalfedge = Halfedge_handle(); +} + +template +void MergeEdgeCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) +{ + if (this->isFirst) + { // save the first edge if mergeable + Halfedge_handle halfedge = this->getNearestMergeableCurve(event); + if (halfedge == Halfedge_handle()) { return; } + this->isFirst = false; + this->mergeableHalfedge = halfedge; + } + else + { + Halfedge_handle nextHalfedge = + this->getNearestMergeableCurve(this->mergeableHalfedge, event); + this->mergeEdge.mergeEdge(this->arr, this->mergeableHalfedge, nextHalfedge); + this->reset(); + } + + Q_EMIT modelChanged(); +} + +template +void MergeEdgeCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) +{ + if (this->isFirst) + { + Halfedge_handle halfedge = this->getNearestMergeableCurve(event); + if (halfedge == Halfedge_handle()) { return; } + this->highlightedCurve->clear(); + this->highlightedCurve->insert(halfedge->curve()); + Q_EMIT modelChanged(); + } + else + { + Halfedge_handle nextHalfedge = + this->getNearestMergeableCurve(this->mergeableHalfedge, event); + + if (nextHalfedge != Halfedge_handle()) + { + this->highlightedCurve2->clear(); + this->highlightedCurve2->insert(nextHalfedge->curve()); + Q_EMIT modelChanged(); + } + } +} + +template +typename MergeEdgeCallback::Halfedge_handle +MergeEdgeCallback::getNearestMergeableCurve( + QGraphicsSceneMouseEvent* event) +{ + // find the nearest curve to the cursor that is adjacent to a curve that + // can be merged with it + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Kernel_point_2; + + Kernel_point_2 p = CGAL::Qt::Converter{}(event->scenePos()); + double minDist = (std::numeric_limits::max)(); + Halfedge_iterator nearestHei; + bool found = false; + + for (Halfedge_iterator hei = this->arr->halfedges_begin(); + hei != this->arr->halfedges_end(); ++hei) + { + Vertex_iterator source = hei->source(); + Vertex_iterator target = hei->target(); + if (source->degree() != 2 && target->degree() != 2) + { // then this halfedge has no mergeable neighbors + continue; + } + Halfedge_handle h1 = hei->prev(); + Halfedge_handle h2 = hei->next(); + if ( + (!this->mergeEdge.areMergeable(this->arr, hei, h1)) && + (!this->mergeEdge.areMergeable(this->arr, hei, h2))) + { continue; } + + X_monotone_curve_2 curve = hei->curve(); + Compute_squared_distance_2 squaredDistance; + squaredDistance.setScene(this->getScene()); + double dist = CGAL::to_double(squaredDistance(p, curve)); + if (!found || dist < minDist) + { + found = true; + minDist = dist; + nearestHei = hei; + } + } + + if (!found) + { // then we did not find a mergeable halfedge + return Halfedge_handle(); + } + return nearestHei; +} + +template +typename MergeEdgeCallback::Halfedge_handle +MergeEdgeCallback::getNearestMergeableCurve( + Halfedge_handle h, QGraphicsSceneMouseEvent* event) +{ + // find the nearest curve to the cursor that is adjacent to a curve that + // can be merged with it + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Kernel_point_2; + + Kernel_point_2 p = CGAL::Qt::Converter{}(event->scenePos()); + Halfedge_handle h1 = h->prev(); + Halfedge_handle h2 = h->next(); + Vertex_iterator source = h->source(); + Vertex_iterator target = h->target(); + + if (source->degree() != 2 && target->degree() != 2) + return Halfedge_handle(); + else if (source->degree() != 2) + return h2; + else if (target->degree() != 2) + return h1; + else if ( + this->mergeEdge.areMergeable(arr, h, h1) && + this->mergeEdge.areMergeable(arr, h, h2)) + { + X_monotone_curve_2 c1 = h1->curve(); + X_monotone_curve_2 c2 = h2->curve(); + Compute_squared_distance_2 squaredDistance; + squaredDistance.setScene(this->getScene()); + double d1 = CGAL::to_double(squaredDistance(p, c1)); + double d2 = CGAL::to_double(squaredDistance(p, c2)); + + return (d1 < d2) ? h1 : h2; + } + else if (this->mergeEdge.areMergeable(arr, h, h2)) + return h2; + else if (this->mergeEdge.areMergeable(arr, h, h1)) + return h1; + else + return Halfedge_handle(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.h index cfc96a16cb4..384cbdfe7bb 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/MergeEdgeCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,237 +7,31 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef MERGE_EDGE_CALLBACK_H #define MERGE_EDGE_CALLBACK_H #include "Callback.h" -#include -#include -#include -#include -#include "CurveGraphicsItem.h" -#include -#include "Utils.h" +#include + +namespace demo_types +{ +enum class TraitsType : int; +} /** Handles merging of arrangement curves selected from the scene. - - The template parameter is a CGAL::Arrangement_with_history_2 of some type. */ -template < typename Arr_ > -class MergeEdgeCallback : public CGAL::Qt::Callback +class MergeEdgeCallbackBase : public CGAL::Qt::Callback { public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Kernel::Segment_2 Segment; - - MergeEdgeCallback( Arrangement* arr_, QObject* parent_ ); - void setScene( QGraphicsScene* scene_ ); - QGraphicsScene* getScene( ) const; - void reset( ); + static MergeEdgeCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); protected: - void mousePressEvent( QGraphicsSceneMouseEvent* event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent* event ); - Halfedge_handle getNearestMergeableCurve( QGraphicsSceneMouseEvent* event ); - Halfedge_handle getNearestMergeableCurve( Halfedge_handle h, - QGraphicsSceneMouseEvent* event ); + using CGAL::Qt::Callback::Callback; +}; - Compute_squared_distance_2< Traits > squaredDistance; - CGAL::Qt::Converter< Kernel > convert; - QGraphicsScene* scene; - CGAL::Qt::CurveGraphicsItem< Traits >* highlightedCurve; - CGAL::Qt::CurveGraphicsItem< Traits >* highlightedCurve2; - Arrangement* arr; - Halfedge_handle mergeableHalfedge; - bool isFirst; -}; // class MergeEdgeCallback - -/*! Constructor */ -template < typename Arr_ > -MergeEdgeCallback< Arr_ >::MergeEdgeCallback( Arrangement* arr_, - QObject* parent_ ) : - CGAL::Qt::Callback( parent_ ), - scene( NULL ), - highlightedCurve( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ), - highlightedCurve2( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ), - arr( arr_ ), - isFirst( true ) -{ - QObject::connect( this, SIGNAL( modelChanged( ) ), - this->highlightedCurve, SLOT( modelChanged( ) ) ); - QObject::connect( this, SIGNAL( modelChanged( ) ), - this->highlightedCurve2, SLOT( modelChanged( ) ) ); -} - -template < typename Arr_ > -void MergeEdgeCallback< Arr_ >::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; - this->highlightedCurve->setScene( scene_ ); - this->highlightedCurve2->setScene( scene_ ); - if ( this->scene ) - { - this->scene->addItem( this->highlightedCurve ); - this->scene->addItem( this->highlightedCurve2 ); - } -} - -template < typename Arr_ > -QGraphicsScene* MergeEdgeCallback< Arr_ >::getScene( ) const -{ - return this->scene; -} - -template < typename Arr_ > -void MergeEdgeCallback< Arr_ >::reset( ) -{ - this->isFirst = true; - this->highlightedCurve->clear( ); - this->highlightedCurve2->clear( ); - this->mergeableHalfedge = Halfedge_handle( ); - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void MergeEdgeCallback::mousePressEvent(QGraphicsSceneMouseEvent* event) -{ - if ( this->isFirst ) - { // save the first edge if mergeable - Halfedge_handle halfedge = this->getNearestMergeableCurve( event ); - if ( halfedge == Halfedge_handle( ) ) - { - return; - } - this->isFirst = false; - this->mergeableHalfedge = halfedge; - } - else - { - Halfedge_handle nextHalfedge = - this->getNearestMergeableCurve( this->mergeableHalfedge, event ); - this->arr->merge_edge( this->mergeableHalfedge, nextHalfedge ); - this->reset( ); - } - - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void MergeEdgeCallback::mouseMoveEvent(QGraphicsSceneMouseEvent* event) -{ - if ( this->isFirst ) - { - Halfedge_handle halfedge = this->getNearestMergeableCurve( event ); - if ( halfedge == Halfedge_handle( ) ) - { - return; - } - this->highlightedCurve->clear( ); - this->highlightedCurve->insert( halfedge->curve( ) ); - Q_EMIT modelChanged( ); - } - else - { - Halfedge_handle nextHalfedge = - this->getNearestMergeableCurve( this->mergeableHalfedge, event ); - this->highlightedCurve2->clear( ); - this->highlightedCurve2->insert( nextHalfedge->curve( ) ); - Q_EMIT modelChanged( ); - } -} - -template < typename Arr_ > -typename MergeEdgeCallback< Arr_ >::Halfedge_handle -MergeEdgeCallback< Arr_ >:: -getNearestMergeableCurve( QGraphicsSceneMouseEvent* event ) -{ - // find the nearest curve to the cursor that is adjacent to a curve that - // can be merged with it - Kernel_point_2 p = this->convert( event->scenePos( ) ); - double minDist = 0.0; - bool noneFound = true; - Halfedge_iterator nearestHei; - - for ( Halfedge_iterator hei = this->arr->halfedges_begin( ); - hei != this->arr->halfedges_end( ); - ++hei ) - { - Vertex_iterator source = hei->source( ); - Vertex_iterator target = hei->target( ); - if ( source->degree( ) != 2 && target->degree( ) != 2 ) - { // then this halfedge has no mergeable neighbors - continue; - } - Halfedge_handle h1 = hei->prev( ); - Halfedge_handle h2 = hei->next( ); - if ( (! this->arr->are_mergeable( hei, h1 ) ) && - (! this->arr->are_mergeable( hei, h2 ) ) ) - { - continue; - } - - X_monotone_curve_2 curve = hei->curve( ); - double dist = CGAL::to_double( this->squaredDistance( p, curve ) ); - if ( noneFound || dist < minDist ) - { - noneFound = false; - minDist = dist; - nearestHei = hei; - } - } - - if ( noneFound ) - { // then we did not find a mergeable halfedge - return Halfedge_handle( ); - } - return nearestHei; -} - -template < typename Arr_ > -typename MergeEdgeCallback< Arr_ >::Halfedge_handle -MergeEdgeCallback< Arr_ >:: -getNearestMergeableCurve( Halfedge_handle h, QGraphicsSceneMouseEvent* event ) -{ - // find the nearest curve to the cursor that is adjacent to a curve that - // can be merged with it - Kernel_point_2 p = this->convert( event->scenePos( ) ); - Halfedge_handle h1 = h->prev( ); - Halfedge_handle h2 = h->next( ); - Vertex_iterator source = h->source( ); - Vertex_iterator target = h->target( ); - if ( source->degree( ) != 2 && target->degree( ) != 2 ) - { - return Halfedge_handle( ); - } - else if ( source->degree( ) != 2 ) - { - return h2; - } - else if ( target->degree( ) != 2 ) - { - return h1; - } - else - { - X_monotone_curve_2 c1 = h1->curve( ); - X_monotone_curve_2 c2 = h2->curve( ); - double d1 = CGAL::to_double( this->squaredDistance( p, c1 ) ); - double d2 = CGAL::to_double( this->squaredDistance( p, c2 ) ); - return ( d1 < d2 ) ? h1 : h2; - } -} #endif // MERGE_EDGE_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.cpp index f0daef178fc..a5a9128c968 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.cpp @@ -11,28 +11,44 @@ #include "NewTabDialog.h" #include "ArrangementDemoWindow.h" +#include "ArrangementTypesUtils.h" #include "ui_NewTabDialog.h" #include -NewTabDialog::NewTabDialog( QWidget* parent, Qt::WindowFlags f) : - QDialog( parent, f ), + +NewTabDialog::NewTabDialog( QWidget* parent ) : + QDialog( parent ), ui( new Ui::NewTabDialog ), buttonGroup( new QButtonGroup ) { - this->ui->setupUi( this ); + using TraitsType = demo_types::TraitsType; - this->buttonGroup->addButton( this->ui->segmentRadioButton, - ArrangementDemoWindow::SEGMENT_TRAITS ); - this->buttonGroup->addButton( this->ui->polylineRadioButton, - ArrangementDemoWindow::POLYLINE_TRAITS ); - this->buttonGroup->addButton( this->ui->conicRadioButton, - ArrangementDemoWindow::CONIC_TRAITS ); - this->buttonGroup->addButton( this->ui->linearRadioButton, - ArrangementDemoWindow::LINEAR_TRAITS ); - this->buttonGroup->addButton( this->ui->circularArcRadioButton, - ArrangementDemoWindow::CIRCULAR_ARC_TRAITS ); - // this->buttonGroup->addButton( this->ui->algebraicRadioButton, - // ArrangementDemoWindow::ALGEBRAIC_TRAITS ); + this->ui->setupUi(this); + + this->buttonGroup->addButton( + this->ui->segmentRadioButton, static_cast(TraitsType::SEGMENT_TRAITS)); + this->buttonGroup->addButton( + this->ui->polylineRadioButton, + static_cast(TraitsType::POLYLINE_TRAITS)); + this->buttonGroup->addButton( + this->ui->linearRadioButton, static_cast(TraitsType::LINEAR_TRAITS)); +#ifdef CGAL_USE_CORE + this->buttonGroup->addButton( + this->ui->conicRadioButton, static_cast(TraitsType::CONIC_TRAITS)); + this->buttonGroup->addButton( + this->ui->algebraicRadioButton, + static_cast(TraitsType::ALGEBRAIC_TRAITS)); + this->buttonGroup->addButton( + this->ui->bezierRadioButton, static_cast(TraitsType::BEZIER_TRAITS)); + this->buttonGroup->addButton( + this->ui->rationalFunctionRadioButton, + static_cast(TraitsType::RATIONAL_FUNCTION_TRAITS)); +#else + this->ui->conicRadioButton->hide(); + this->ui->algebraicRadioButton->hide(); + this->ui->bezierRadioButton->hide(); + this->ui->rationalFunctionRadioButton->hide(); +#endif } int NewTabDialog::checkedId( ) const diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.h index 679f30a7887..11e485fcc22 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.h @@ -23,7 +23,7 @@ namespace Ui class NewTabDialog : public QDialog { public: - NewTabDialog( QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowType(0) ); + NewTabDialog( QWidget* parent = 0 ); int checkedId( ) const; protected: diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.ui b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.ui index c9569d1c6ef..6e3b767e903 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.ui +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/NewTabDialog.ui @@ -7,7 +7,7 @@ 0 0 400 - 215 + 249 @@ -19,7 +19,7 @@ 10 10 381 - 197 + 230 @@ -44,13 +44,41 @@ + + + Linear + + + + Conic + + + + Algebraic + + + + + + + Bezier + + + + + + Rational Functions + + + + Qt::Horizontal @@ -60,27 +88,6 @@ - - - - Linear - - - - - - - Circular Arc - - - - - - - - - - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.cpp index f591b4ad677..f91da6d8b69 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.cpp @@ -1,15 +1,17 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "OverlayDialog.h" #include "ArrangementDemoWindow.h" -#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "QtMetaTypes.h" #include #include @@ -17,13 +19,14 @@ #include "ui_OverlayDialog.h" -// TODO: Don't color the text, but set an icon for each arrangement type... -// TODO: Or maybe don't bother -OverlayDialog::OverlayDialog( ArrangementDemoWindow* parent, - Qt::WindowFlags f ) : - QDialog( parent, f ), - ui( new Ui::OverlayDialog ) +OverlayDialog::OverlayDialog( + QWidget* parent, const std::vector& arr_infos_) : + QDialog(parent), + arr_infos(arr_infos_), + ui(new Ui::OverlayDialog) { + using namespace demo_types; + // An extra parenthesis around QColor to avoid the // https://en.wikipedia.org/wiki/Most_vexing_parse // on clang @@ -32,74 +35,36 @@ OverlayDialog::OverlayDialog( ArrangementDemoWindow* parent, QBrush conicColor( ( QColor( ::Qt::blue ) ) ); this->ui->setupUi( this ); - std::vector< QString > labels = parent->getTabLabels( ); - std::vector< CGAL::Object > arrangements = parent->getArrangements( ); - - for ( unsigned int i = 0; i < labels.size( ); ++i ) + for (std::size_t i = 0; i < arr_infos.size(); i++) { + auto& arr = arr_infos[i]; + QListWidgetItem* item = new QListWidgetItem( this->ui->arrangementsListWidget ); - item->setText( labels[ i ] ); - item->setData( ARRANGEMENT, QVariant::fromValue( arrangements[ i ] ) ); + item->setText(arr.label); + item->setData(ARRANGEMENT, QVariant::fromValue(i)); + + static constexpr std::array icons = { + ":/cgal/icons/green_icon.xpm", ":/cgal/icons/yellow_icon.xpm", + ":/cgal/icons/blue_icon.xpm", ":/cgal/icons/red_icon.xpm", + ":/cgal/icons/pink_icon.xpm"}; + QIcon icon; - Seg_arr* seg; - Pol_arr* pol; + icon.addFile( + QString::fromUtf8(icons[static_cast(arr.ttype) % icons.size()])); -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif - - Lin_arr* lin; - Arc_arr* arc; - // Alg_seg_arr* alg; - if ( CGAL::assign( seg, arrangements[ i ] ) ) - { - icon.addFile(QString::fromUtf8(":/icons/green_icon.xpm"), QSize(), - QIcon::Normal, QIcon::Off); - } - else if ( CGAL::assign( pol, arrangements[ i ] ) ) - { - icon.addFile(QString::fromUtf8(":/icons/yellow_icon.xpm"), QSize(), - QIcon::Normal, QIcon::Off); - } - -#ifdef CGAL_USE_CORE - else if ( CGAL::assign( conic, arrangements[ i ] ) ) - { - icon.addFile(QString::fromUtf8(":/icons/red_icon.xpm"), QSize(), - QIcon::Normal, QIcon::Off); - } -#endif - - else if ( CGAL::assign( lin, arrangements[ i ] ) ) - { - icon.addFile(QString::fromUtf8(":/icons/blue_icon.xpm"), QSize(), - QIcon::Normal, QIcon::Off); - } - else if ( CGAL::assign( arc, arrangements[ i ] ) ) - { - icon.addFile(QString::fromUtf8(":/icons/green_icon.xpm"), QSize(), - QIcon::Normal, QIcon::Off); - } - // else if ( CGAL::assign( alg, arrangements[ i ] ) ) - // { - // icon.addFile(QString::fromUtf8(":/icons/yellow_icon.xpm"), QSize(), - // QIcon::Normal, QIcon::Off); - // } - item->setIcon( icon ); + item->setIcon(icon); } } -std::vector< CGAL::Object > -OverlayDialog::selectedArrangements( ) const +std::vector OverlayDialog::selectedArrangements() const { - std::vector< CGAL::Object > res; - for ( int i = 0; i < this->ui->overlayListWidget->count( ); ++i ) + std::vector res; + for (int i = 0; i < this->ui->overlayListWidget->count(); ++i) { - QListWidgetItem* item = this->ui->overlayListWidget->item( i ); - QVariant data = item->data( ARRANGEMENT ); - CGAL::Object arr = data.value< CGAL::Object >( ); - res.push_back( arr ); + QListWidgetItem* item = this->ui->overlayListWidget->item(i); + size_t arr_idx = item->data(ARRANGEMENT).value(); + res.push_back(this->arr_infos[arr_idx].id); } return res; } @@ -157,135 +122,23 @@ void OverlayDialog::on_unpickPushButton_pressed( ) void OverlayDialog::restrictSelection( QListWidgetItem* item ) { - CGAL::Object o = item->data( ARRANGEMENT ).value< CGAL::Object >( ); - Seg_arr* seg; - Pol_arr* pol; + using namespace demo_types; -#ifdef CGAL_USE_CORE - Conic_arr* conic; -#endif + auto& arr1 = arr_infos[item->data(ARRANGEMENT).value()]; - Lin_arr* lin; - Arc_arr* arc; - // Alg_seg_arr* alg; - if ( CGAL::assign( seg, o ) ) + for (int i = 0; i < this->ui->arrangementsListWidget->count(); ++i) { - for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - { - QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - bool enabled = CGAL::assign( seg, o2 ); - Qt::ItemFlags flags = otherItem->flags( ); - if ( ! enabled ) - { - flags &= ~( Qt::ItemIsEnabled ); - } - else - { - flags |= Qt::ItemIsEnabled; - } - otherItem->setFlags( flags ); - } - } - else if ( CGAL::assign( pol, o ) ) - { - for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - { - QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - bool enabled = CGAL::assign( pol, o2 ); - Qt::ItemFlags flags = otherItem->flags( ); - if ( ! enabled ) - { - flags &= ~( Qt::ItemIsEnabled ); - } - else - { - flags |= Qt::ItemIsEnabled; - } - otherItem->setFlags( flags ); - } - } + auto* otherItem = this->ui->arrangementsListWidget->item(i); + auto& arr2 = arr_infos[otherItem->data(ARRANGEMENT).value()]; + bool enabled = (arr1.ttype == arr2.ttype); -#ifdef CGAL_USE_CORE - else if ( CGAL::assign( conic, o ) ) - { - for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - { - QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - bool enabled = CGAL::assign( conic, o2 ); - Qt::ItemFlags flags = otherItem->flags( ); - if ( ! enabled ) - { - flags &= ~( Qt::ItemIsEnabled ); - } - else - { - flags |= Qt::ItemIsEnabled; - } - otherItem->setFlags( flags ); - } + Qt::ItemFlags flags = otherItem->flags(); + if (!enabled) + flags &= ~(Qt::ItemIsEnabled); + else + flags |= Qt::ItemIsEnabled; + otherItem->setFlags(flags); } -#endif - - else if ( CGAL::assign( lin, o ) ) - { - for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - { - QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - bool enabled = CGAL::assign( lin, o2 ); - Qt::ItemFlags flags = otherItem->flags( ); - if ( ! enabled ) - { - flags &= ~( Qt::ItemIsEnabled ); - } - else - { - flags |= Qt::ItemIsEnabled; - } - otherItem->setFlags( flags ); - } - } - else if ( CGAL::assign( arc, o ) ) - { - for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - { - QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - bool enabled = CGAL::assign( arc, o2 ); - Qt::ItemFlags flags = otherItem->flags( ); - if ( ! enabled ) - { - flags &= ~( Qt::ItemIsEnabled ); - } - else - { - flags |= Qt::ItemIsEnabled; - } - otherItem->setFlags( flags ); - } - } - // else if ( CGAL::assign( alg, o ) ) - // { - // for ( int i = 0; i < this->ui->arrangementsListWidget->count( ); ++i ) - // { - // QListWidgetItem* otherItem = this->ui->arrangementsListWidget->item( i ); - // CGAL::Object o2 = otherItem->data( ARRANGEMENT ).value< CGAL::Object >( ); - // bool enabled = CGAL::assign( alg, o2 ); - // Qt::ItemFlags flags = otherItem->flags( ); - // if ( ! enabled ) - // { - // flags &= ~( Qt::ItemIsEnabled ); - // } - // else - // { - // flags |= Qt::ItemIsEnabled; - // } - // otherItem->setFlags( flags ); - // } - // } } void OverlayDialog::unrestrictSelection( ) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.h index fb1c45ea1bb..388c016df88 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/OverlayDialog.h @@ -20,18 +20,29 @@ class ArrangementDemoWindow; class QListWidgetItem; namespace Ui { class OverlayDialog; } +namespace demo_types +{ +enum class TraitsType : int; +} + class OverlayDialog : public QDialog { Q_OBJECT - public: +public: typedef enum OverlayDialogRole { ARRANGEMENT = 32 } OverlayDialogRole; - OverlayDialog( ArrangementDemoWindow* parent, Qt::WindowFlags f = Qt::WindowType(0) ); + struct ArrangementInfo + { + int id; + demo_types::TraitsType ttype; + QString label; + }; + OverlayDialog(QWidget* parent, const std::vector&); - std::vector< CGAL::Object > selectedArrangements( ) const; + std::vector selectedArrangements() const; public Q_SLOTS: void on_pickPushButton_pressed( ); @@ -41,6 +52,8 @@ protected: void restrictSelection( QListWidgetItem* item ); void unrestrictSelection( ); + std::vector arr_infos; + Ui::OverlayDialog* ui; }; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp new file mode 100644 index 00000000000..6e2763f02fc --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.cpp @@ -0,0 +1,207 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include "PointLocationCallback.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveGraphicsItem.h" +#include "Utils/PointLocationFunctions.h" + +#include + +#include +#include + +/** + Supports visualization of point location on arrangements. + + The template parameter is a CGAL::Arrangement_with_history_2 of some type. +*/ +template +class PointLocationCallback : public PointLocationCallbackBase +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Halfedge_handle Halfedge_handle; + typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; + typedef typename Arrangement::Face_handle Face_handle; + typedef typename Arrangement::Face_const_handle Face_const_handle; + typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement::Halfedge_around_vertex_const_circulator + Halfedge_around_vertex_const_circulator; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Arrangement::Curve_handle Curve_handle; + typedef + typename Arrangement::Originating_curve_iterator Originating_curve_iterator; + typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; + typedef typename Arrangement::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + PointLocationCallback(Arrangement* arr_, QObject* parent_); + void reset(); + void setScene(QGraphicsScene* scene_); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event); + void mouseMoveEvent(QGraphicsSceneMouseEvent* event); + void highlightPointLocation(QGraphicsSceneMouseEvent* event); + + void highlightPointLocation( + QGraphicsSceneMouseEvent* event, CGAL::Arr_oblivious_side_tag); + void highlightPointLocation( + QGraphicsSceneMouseEvent* event, CGAL::Arr_open_side_tag); + + Arrangement* arr; + CGAL::Qt::CurveGraphicsItem* highlightedCurves; +}; // class PointLocationCallback + +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new PointLocationCallback(arr, parent); + } + + PointLocationCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +PointLocationCallbackBase* PointLocationCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + PointLocationCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +/*! Constructor */ +template +PointLocationCallback::PointLocationCallback( + Arrangement* arr_, QObject* parent_) : + PointLocationCallbackBase(parent_), + arr(arr_), highlightedCurves(new CGAL::Qt::CurveGraphicsItem()) +{ + QObject::connect( + this, SIGNAL(modelChanged()), this->highlightedCurves, + SLOT(modelChanged())); +} + +template +void PointLocationCallback::setScene(QGraphicsScene* scene_) +{ + this->scene = scene_; + this->highlightedCurves->setScene(scene_); + if (this->scene) { this->scene->addItem(this->highlightedCurves); } +} + +template +void PointLocationCallback::reset() +{ + this->highlightedCurves->clear(); + Q_EMIT modelChanged(); +} + +template +void PointLocationCallback::mousePressEvent( + QGraphicsSceneMouseEvent* event) +{ + this->highlightPointLocation(event); +} + +template +void PointLocationCallback::mouseMoveEvent( + QGraphicsSceneMouseEvent* /* event */) +{ +} + +template +void PointLocationCallback::highlightPointLocation( + QGraphicsSceneMouseEvent* event) +{ + typename Traits::Left_side_category category; + this->highlightPointLocation(event, category); + + Q_EMIT modelChanged(); +} + +template +void PointLocationCallback::highlightPointLocation( + QGraphicsSceneMouseEvent* event, CGAL::Arr_oblivious_side_tag) +{ + Face_const_handle face = + PointLocationFunctions{}.getFace(this->arr, event->scenePos()); + + this->highlightedCurves->clear(); + if (!face->is_unbounded()) + { // it is an interior face; highlight its border + Ccb_halfedge_const_circulator cc = face->outer_ccb(); + do + { + X_monotone_curve_2 curve = cc->curve(); + this->highlightedCurves->insert(curve); + } while (++cc != face->outer_ccb()); + } + Hole_const_iterator hit; + Hole_const_iterator eit = face->holes_end(); + for (hit = face->holes_begin(); hit != eit; ++hit) + { // highlight any holes inside this face + Ccb_halfedge_const_circulator cc = *hit; + do + { + X_monotone_curve_2 curve = cc->curve(); + this->highlightedCurves->insert(curve); + cc++; + } while (cc != *hit); + } +} + +template +void PointLocationCallback::highlightPointLocation( + QGraphicsSceneMouseEvent* event, CGAL::Arr_open_side_tag) +{ + Face_const_handle face = + PointLocationFunctions{}.getFace(this->arr, event->scenePos()); + + this->highlightedCurves->clear(); + Ccb_halfedge_const_circulator cc = face->outer_ccb(); + do + { + if (!cc->is_fictitious()) + { + X_monotone_curve_2 curve = cc->curve(); + this->highlightedCurves->insert(curve); + } + } while (++cc != face->outer_ccb()); + Hole_const_iterator hit; + Hole_const_iterator eit = face->holes_end(); + for (hit = face->holes_begin(); hit != eit; ++hit) + { // highlight any holes inside this face + Ccb_halfedge_const_circulator cc = *hit; + do + { + X_monotone_curve_2 curve = cc->curve(); + this->highlightedCurves->insert(curve); + cc++; + } while (cc != *hit); + } +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.h index dd5f4d7a5c2..dcf1d0e9346 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointLocationCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,302 +7,28 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef POINT_LOCATION_CALLBACK_H #define POINT_LOCATION_CALLBACK_H +#include #include "Callback.h" -#include -#include -#include -#include -#include -#include "CurveGraphicsItem.h" -#include -#include -#include -#include -#include -#include -#include "Utils.h" +namespace demo_types +{ +enum class TraitsType : int; +} -/** - Supports visualization of point location on arrangements. - - The template parameter is a CGAL::Arrangement_with_history_2 of some type. -*/ -template < typename Arr_ > -class PointLocationCallback : public CGAL::Qt::Callback +class PointLocationCallbackBase : public CGAL::Qt::Callback { public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Face_handle Face_handle; - typedef typename Arrangement::Face_const_handle Face_const_handle; - typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Arrangement::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename CGAL::Arr_trapezoid_ric_point_location< Arrangement > - TrapezoidPointLocationStrategy; - typedef typename CGAL::Arr_simple_point_location< Arrangement > - SimplePointLocationStrategy; - typedef typename CGAL::Arr_walk_along_line_point_location< Arrangement > - Walk_pl_strategy; - typedef typename Supports_landmarks< Arrangement >::LandmarksType - LandmarksPointLocationStrategy; - - PointLocationCallback( Arrangement* arr_, QObject* parent_ ); - void reset( ); - void setScene( QGraphicsScene* scene_ ); + static PointLocationCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); protected: - void mousePressEvent( QGraphicsSceneMouseEvent *event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent *event ); - void highlightPointLocation( QGraphicsSceneMouseEvent *event ); - void highlightPointLocation( QGraphicsSceneMouseEvent *event, - CGAL::Arr_oblivious_side_tag ); - void highlightPointLocation( QGraphicsSceneMouseEvent *event, - CGAL::Arr_open_side_tag ); - Face_const_handle getFace( const CGAL::Object& o ); - CGAL::Object locate( const Kernel_point_2& point ); - CGAL::Object locate( const Kernel_point_2& point, - CGAL::Tag_false /*supportsLandmarks*/ ); - CGAL::Object locate( const Kernel_point_2& point, - CGAL::Tag_true /*doesNotSupportLandmarks*/ ); - - using Callback::scene; - CGAL::Qt::Converter< Kernel > convert; - CGAL::Object pointLocationStrategy; - Arrangement* arr; - CGAL::Qt::CurveGraphicsItem< Traits >* highlightedCurves; - Arr_construct_point_2< Traits > toArrPoint; -}; // class PointLocationCallback - -/*! Constructor */ -template < typename Arr_ > -PointLocationCallback< Arr_ >:: -PointLocationCallback( Arrangement* arr_, QObject* parent_ ) : - CGAL::Qt::Callback( parent_ ), - pointLocationStrategy( CGAL::make_object( new Walk_pl_strategy( *arr_ ) ) ), - arr( arr_ ), - highlightedCurves( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ) -{ - QObject::connect( this, SIGNAL( modelChanged( ) ), - this->highlightedCurves, SLOT( modelChanged( ) ) ); -} - -template < typename Arr_ > -void -PointLocationCallback< Arr_ >:: -setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; - this->highlightedCurves->setScene( scene_ ); - if ( this->scene ) - { - this->scene->addItem( this->highlightedCurves ); - } -} - -template < typename Arr_ > -void -PointLocationCallback< Arr_ >:: -reset( ) -{ - this->highlightedCurves->clear( ); - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void -PointLocationCallback< Arr_ >:: -mousePressEvent( QGraphicsSceneMouseEvent* event ) -{ - this->highlightPointLocation( event ); -} - -template < typename Arr_ > -void PointLocationCallback< Arr_ >:: -mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) -{ } - -template < typename Arr_ > -void PointLocationCallback< Arr_ >:: -highlightPointLocation( QGraphicsSceneMouseEvent* event ) -{ - typename Traits::Left_side_category category; - this->highlightPointLocation( event, category ); - - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void PointLocationCallback< Arr_ >:: -highlightPointLocation( QGraphicsSceneMouseEvent *event, - CGAL::Arr_oblivious_side_tag ) -{ - Kernel_point_2 point = this->convert( event->scenePos( ) ); - - CGAL::Object pointLocationResult = this->locate( point ); - Face_const_handle face = this->getFace( pointLocationResult ); - this->highlightedCurves->clear( ); - if ( ! face->is_unbounded( ) ) - { // it is an interior face; highlight its border - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - X_monotone_curve_2 curve = cc->curve( ); - this->highlightedCurves->insert( curve ); - } while ( ++cc != face->outer_ccb( ) ); - } - Hole_const_iterator hit; - Hole_const_iterator eit = face->holes_end( ); - for ( hit = face->holes_begin( ); hit != eit; ++hit ) - { // highlight any holes inside this face - Ccb_halfedge_const_circulator cc = *hit; - do - { - X_monotone_curve_2 curve = cc->curve( ); - this->highlightedCurves->insert( curve ); - cc++; - } - while ( cc != *hit ); - } -} - -template < typename Arr_ > -void PointLocationCallback< Arr_ >:: -highlightPointLocation( QGraphicsSceneMouseEvent *event, - CGAL::Arr_open_side_tag ) -{ - Kernel_point_2 point = this->convert( event->scenePos( ) ); - CGAL::Object pointLocationResult = this->locate( point ); - Face_const_handle face = this->getFace( pointLocationResult ); - this->highlightedCurves->clear( ); - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - if ( ! cc->is_fictitious( ) ) - { - X_monotone_curve_2 curve = cc->curve( ); - this->highlightedCurves->insert( curve ); - } - } while ( ++cc != face->outer_ccb( ) ); - Hole_const_iterator hit; - Hole_const_iterator eit = face->holes_end( ); - for ( hit = face->holes_begin( ); hit != eit; ++hit ) - { // highlight any holes inside this face - Ccb_halfedge_const_circulator cc = *hit; - do - { - X_monotone_curve_2 curve = cc->curve( ); - this->highlightedCurves->insert( curve ); - cc++; - } - while ( cc != *hit ); - } -} - -template < typename Arr_ > -typename PointLocationCallback< Arr_ >::Face_const_handle -PointLocationCallback< Arr_ >::getFace( const CGAL::Object& obj ) -{ - Face_const_handle f; - if ( CGAL::assign( f, obj ) ) - return f; - - Halfedge_const_handle he; - if (CGAL::assign( he, obj )) - return (he->face( )); - - Vertex_const_handle v; - CGAL_assertion(CGAL::assign( v, obj )); - CGAL::assign( v, obj ); - if ( v->is_isolated( ) ) - return v->face( ); - Halfedge_around_vertex_const_circulator eit = v->incident_halfedges( ); - return (eit->face( )); -} - -template < typename Arr_ > -CGAL::Object PointLocationCallback::locate(const Kernel_point_2& point) -{ - typename Supports_landmarks< Arrangement >::Tag supportsLandmarks; - return this->locate( point, supportsLandmarks ); -} - -template < typename Arr_ > -CGAL::Object PointLocationCallback< Arr_ >::locate( const Kernel_point_2& pt, - CGAL::Tag_true ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - LandmarksPointLocationStrategy* landmarksStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->locate( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->locate( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->locate( point ); - } - else if ( CGAL::assign( landmarksStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = landmarksStrategy->locate( point ); - } - return pointLocationResult; -} - -template < typename Arr_ > -CGAL::Object PointLocationCallback< Arr_ >::locate( const Kernel_point_2& pt, - CGAL::Tag_false ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->locate( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->locate( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->locate( point ); - } - return pointLocationResult; -} + using CGAL::Qt::Callback::Callback; +}; #endif // POINT_LOCATION_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.cpp new file mode 100644 index 00000000000..9194c35a749 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.cpp @@ -0,0 +1,268 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include +#include + +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "PointSnapper.h" + +#include + +template +class PointSnapper : public PointSnapperBase +{ + using Arrangement = Arr_; + using Compute_squared_distance_2 = Rat_kernel::Compute_squared_distance_2; + +public: + PointSnapper(QGraphicsScene*, GridGraphicsItem*, Arrangement*); + boost::optional snapToArrangement(const QPointF& qpt) override; + +private: + Arrangement* arr; +}; + +PointSnapperBase::PointSnapperBase( + QGraphicsScene* scene, GridGraphicsItem* grid) : + GraphicsSceneMixin(scene), + gridGraphicsItem{grid}, snapToGridEnabled{false}, + snapToArrangementEnabled{false} +{ +} + +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new PointSnapper(scene, grid, arr); + } + + PointSnapperBase*& res; + QGraphicsScene* scene; + GridGraphicsItem* grid; + CGAL::Object& arr_obj; +}; +} // anonymous namespace + +PointSnapperBase* PointSnapperBase::create( + demo_types::TraitsType tt, QGraphicsScene* scene, GridGraphicsItem* grid, + CGAL::Object arr_obj) +{ + PointSnapperBase* res; + ExplicitLambda explicit_lambda{res, scene, grid, arr_obj}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +auto PointSnapperBase::snapPoint(const QPointF& qpt) -> Point_2 +{ + if (this->snapToGridEnabled && this->snapToArrangementEnabled) + { + Point_2 pt = {qpt.x(), qpt.y()}; + auto gridPt = snapToGrid(qpt); + auto arrPt = snapToArrangement(qpt); + if (!arrPt) + return gridPt; + else if ( + compute_squared_distance_2(pt, gridPt) < + compute_squared_distance_2(pt, *arrPt)) + return gridPt; + else + return *arrPt; + } + else if (this->snapToGridEnabled) + { + return snapToGrid(qpt); + } + else if (this->snapToArrangementEnabled) + { + auto arrPt = snapToArrangement(qpt); + if (arrPt) + return *snapToArrangement(qpt); + else + return {qpt.x(), qpt.y()}; + } + else + return Point_2{qpt.x(), qpt.y()}; +} + +// snap to grid without loss of precision +auto PointSnapperBase::snapToGrid(const QPointF& qpt) -> Point_2 +{ + Rational two{2}; + Rational five{5}; + Rational half{0.5}; + // can't use 0.2 since it's not perfectly representable as a float/double + Rational fifth{Rational{1} / five}; + + Rational x; + { + int a = gridGraphicsItem->getXPower2(); + int b = gridGraphicsItem->getXPower5(); + // we have to calculate l in BigRat to be exact + Rational lx; + if (a < 0) + lx = CGAL::ipower(half, -a); + else + lx = CGAL::ipower(two, a); + if (b < 0) + lx *= CGAL::ipower(fifth, -b); + else + lx *= CGAL::ipower(five, b); + x = lx * std::lround(CGAL::to_double(Rational(qpt.x()) / lx)); + } + + Rational y; + { + int a = gridGraphicsItem->getYPower2(); + int b = gridGraphicsItem->getYPower5(); + // we have to calculate l in BigRat to be exact + Rational ly; + if (a < 0) + ly = CGAL::ipower(half, -a); + else + ly = CGAL::ipower(two, a); + if (b < 0) + ly *= CGAL::ipower(fifth, -b); + else + ly *= CGAL::ipower(five, b); + y = ly * std::lround(CGAL::to_double(Rational(qpt.y()) / ly)); + } + + return Point_2{x, y}; +} + +void PointSnapperBase::setSnapToGrid(bool val) +{ + this->snapToGridEnabled = val; +} +void PointSnapperBase::setSnapToArrangement(bool val) +{ + this->snapToArrangementEnabled = val; +} +bool PointSnapperBase::isSnapToGridEnabled() { return this->snapToGridEnabled; } +bool PointSnapperBase::isSnapToArrangementEnabled() +{ + return this->snapToArrangementEnabled; +} + +template +PointSnapper::PointSnapper( + QGraphicsScene* scene, GridGraphicsItem* grid, Arrangement* arr_) : + PointSnapperBase(scene, grid), + arr{arr_} +{ +} + +template +inline boost::optional snapToArrangement( + const QPointF& qpt, const QTransform& worldTransform, Arrangement* arr) +{ + using Point_2 = PointSnapperBase::Point_2; + using Rational = PointSnapperBase::Rational; + using Compute_squared_distance_2 = + PointSnapperBase::Compute_squared_distance_2; + + Compute_squared_distance_2 compute_squared_distance_2; + + Point_2 initialPoint{qpt.x(), qpt.y()}; + Point_2 closestPoint = initialPoint; + + bool first = true; + Rational minDist(0); + + static constexpr int PIXEL_RADIUS = 15; + Rational maxDist = + PIXEL_RADIUS * PIXEL_RADIUS * + std::abs(1 / (worldTransform.m11() * worldTransform.m22())); + + for (auto vit = arr->vertices_begin(); vit != arr->vertices_end(); ++vit) + { + auto arr_point = vit->point(); + Point_2 point{arr_point.x(), arr_point.y()}; + auto dist = compute_squared_distance_2(initialPoint, point); + if (first || (dist < minDist)) + { + first = false; + minDist = dist; + closestPoint = point; + } + } + + if (!first && minDist < maxDist) + return closestPoint; + else + return {}; +} + +template +struct SnapToArrangement +{ + using Point_2 = PointSnapperBase::Point_2; + template + boost::optional + operator()(const QPointF& qpt, const QTransform&, Arrangement*) + { + return Point_2{qpt.x(), qpt.y()}; + } +}; +template +struct SnapToArrangement> +{ + using Point_2 = PointSnapperBase::Point_2; + template + boost::optional operator()( + const QPointF& qpt, const QTransform& worldTransform, Arrangement* arr) + { + return snapToArrangement(qpt, worldTransform, arr); + } +}; +template +struct SnapToArrangement> +{ + using Point_2 = PointSnapperBase::Point_2; + template + boost::optional operator()( + const QPointF& qpt, const QTransform& worldTransform, Arrangement* arr) + { + return snapToArrangement(qpt, worldTransform, arr); + } +}; +template +struct SnapToArrangement> +{ + using Point_2 = PointSnapperBase::Point_2; + template + boost::optional operator()( + const QPointF& qpt, const QTransform& worldTransform, Arrangement* arr) + { + return snapToArrangement(qpt, worldTransform, arr); + } +}; + +template +auto PointSnapper::snapToArrangement(const QPointF& qpt) + -> boost::optional +{ + using Traits = typename Arrangement::Geometry_traits_2; + auto view = getView(); + if (view) + return SnapToArrangement{}(qpt, view->transform(), arr); + else + return {}; +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.h new file mode 100644 index 00000000000..9829f831f5d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointSnapper.h @@ -0,0 +1,61 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_POINT_SNAPPER_H +#define ARRANGEMENT_DEMO_POINT_SNAPPER_H + +#include "GraphicsSceneMixin.h" +#include "GridGraphicsItem.h" +#include "RationalTypes.h" + +#include + +#include + +namespace demo_types +{ +enum class TraitsType : int; +} + +class GridGraphicsItem; +class QGraphicsScene; + +class PointSnapperBase : public GraphicsSceneMixin +{ +public: + using Rational = demo_types::RationalTypes::Rational; + using Rat_kernel = demo_types::RationalTypes::Rat_kernel; + using Point_2 = demo_types::RationalTypes::Rat_point_2; + using Compute_squared_distance_2 = Rat_kernel::Compute_squared_distance_2; + +public: + static PointSnapperBase* create( + demo_types::TraitsType, QGraphicsScene*, GridGraphicsItem*, + CGAL::Object arr_obj); + + Point_2 snapPoint(const QPointF& qpt); + void setSnapToGrid(bool val); + void setSnapToArrangement(bool val); + bool isSnapToGridEnabled(); + bool isSnapToArrangementEnabled(); + +protected: + PointSnapperBase(QGraphicsScene* scene, GridGraphicsItem* grid); + Point_2 snapToGrid(const QPointF& qpt); + virtual boost::optional snapToArrangement(const QPointF& qpt) = 0; + + GridGraphicsItem* gridGraphicsItem; + bool snapToGridEnabled; + bool snapToArrangementEnabled; + Compute_squared_distance_2 compute_squared_distance_2; +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.cpp index af4fd285260..3de37875794 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "PointsGraphicsItem.h" @@ -15,52 +16,48 @@ #include #include -PointsGraphicsItem::PointsGraphicsItem( ) : - pointRadius( 3.0 ), - color( ::Qt::blue ) -{ } - -void PointsGraphicsItem::paint(QPainter* painter, - const QStyleOptionGraphicsItem* /* option */, - QWidget* /* widget */) +//! A constructor. +PointsGraphicsItem::PointsGraphicsItem(QGraphicsItem* parent) : + QGraphicsItem(parent), pointRadius(3.0), color(::Qt::blue) { - double scale = painter->worldTransform( ).m11( ); - double radius = this->pointRadius; - radius /= scale; - QPen savePen = painter->pen( ); - painter->setBrush( QBrush( this->color ) ); - - for ( unsigned int i = 0; i < this->points.size( ); ++i ) - { - QPointF pt = this->points[ i ]; - painter->drawEllipse( pt, radius, radius ); - } - - painter->setPen( savePen ); } -QRectF PointsGraphicsItem::boundingRect( ) const +void PointsGraphicsItem::paint( + QPainter* painter, const QStyleOptionGraphicsItem* /* option */, + QWidget* /* widget */) { - if ( this->points.size( ) == 0 ) + painter->save(); + + painter->setBrush(QBrush(this->color)); + QTransform matrix = painter->worldTransform(); + painter->resetTransform(); + + for (auto& point : this->points) + painter->drawEllipse( + matrix.map(point), this->pointRadius, this->pointRadius); + + painter->restore(); +} + +QRectF PointsGraphicsItem::boundingRect() const +{ + if (this->points.size() == 0) { return QRectF(); } + double xmin = (std::numeric_limits::max)(); + double xmax = -(std::numeric_limits::max)(); + double ymin = (std::numeric_limits::max)(); + double ymax = -(std::numeric_limits::max)(); + for (unsigned int i = 0; i < this->points.size(); ++i) { - return QRectF( ); + QPointF pt = this->points[i]; + double x = pt.x(); + double y = pt.y(); + xmin = (std::min)(xmin, x); + xmax = (std::max)(xmax, x); + ymin = (std::min)(ymin, y); + ymax = (std::max)(ymax, y); } - double xmin = (std::numeric_limits< double >::max)( ); - double xmax = -(std::numeric_limits< double >::max)( ); - double ymin = (std::numeric_limits< double >::max)( ); - double ymax = -(std::numeric_limits< double >::max)( ); - for ( unsigned int i = 0; i < this->points.size(); ++i ) - { - QPointF pt = this->points[ i ]; - double x = pt.x( ); - double y = pt.y( ); - xmin = (std::min)( xmin, x ); - xmax = (std::max)( xmax, x ); - ymin = (std::min)( ymin, y ); - ymax = (std::max)( ymax, y ); - } - QRectF res( QPointF( xmin, ymin ), QPointF( xmax, ymax ) ); - res.adjust( -5, -5, 5, 5 ); // pad the borders a bit + QRectF res(QPointF(xmin, ymin), QPointF(xmax, ymax)); + res.adjust(-5, -5, 5, 5); // pad the borders a bit return res; } @@ -90,16 +87,3 @@ double PointsGraphicsItem::getPointRadius( ) const { return this->pointRadius; } - -void PointsGraphicsItem::modelChanged( ) -{ - if ( this->points.size( ) == 0 ) - { - this->hide( ); - } - else - { - this->show( ); - } - this->update( ); -} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.h index b82335330c1..7dce869a824 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PointsGraphicsItem.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,57 +7,84 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef POINTS_GRAPHICS_ITEM_H #define POINTS_GRAPHICS_ITEM_H #include -#include +#include #include -#include class QPainter; -class QPen; /** Add a set of points to the QGraphicsScene. */ -class PointsGraphicsItem: public CGAL::Qt::GraphicsItem +class PointsGraphicsItem : public QGraphicsItem { public: - PointsGraphicsItem( ); + PointsGraphicsItem(QGraphicsItem* parent = nullptr); - virtual void paint( QPainter* painter, - const QStyleOptionGraphicsItem* option, QWidget* widget ); - virtual QRectF boundingRect( ) const; + void paint( + QPainter* painter, const QStyleOptionGraphicsItem* option = nullptr, + QWidget* widget = nullptr) override; - template < class Point > - void insert( const Point& point ) - { - this->prepareGeometryChange( ); + QRectF boundingRect() const override; - double x = CGAL::to_double( point.x( ) ); - double y = CGAL::to_double( point.y( ) ); - this->points.push_back( QPointF( x, y ) ); - } + template + inline void insert(const Point& point); - void clear( ); + void clear(); - void setColor( QColor c ); - QColor getColor( ) const; + void setColor(QColor c); + QColor getColor() const; - void setPointRadius( double d ); - double getPointRadius( ) const; - -public Q_SLOTS: - virtual void modelChanged( ); + void setPointRadius(double d); + double getPointRadius() const; protected: - std::vector< QPointF > points; + std::vector points; double pointRadius; QColor color; }; // class PointsGraphicsItem +namespace CGAL +{ +template < + class RatKernel_, class AlgKernel_, class NtTraits_, class BoundingTraits_> +class _Bezier_point_2; +} + +namespace details +{ +struct ApproximatePoint +{ + template + QPointF operator()(const T& point) + { + return QPointF(CGAL::to_double(point.x()), CGAL::to_double(point.y())); + } + + template < + class RatKernel, class AlgKernel, class NtTraits, class BoundingTraits> + QPointF operator()( + const CGAL::_Bezier_point_2& + point) + { + auto xy = point.approximate(); + return QPointF(xy.first, xy.second); + } +}; +} + +template +inline void PointsGraphicsItem::insert(const Point& point) +{ + this->prepareGeometryChange(); + this->points.push_back(details::ApproximatePoint{}(point)); +} + #endif // POINTS_GRAPHICS_ITEM_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PropertyValueDelegate.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PropertyValueDelegate.cpp index da000d5083f..0f2dbb00498 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PropertyValueDelegate.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/PropertyValueDelegate.cpp @@ -10,9 +10,7 @@ // Author(s) : Alex Tsui #include "ColorItemEditor.h" -#include "DeleteCurveModeItemEditor.h" #include "PropertyValueDelegate.h" -#include "DeleteCurveMode.h" #include #include @@ -35,30 +33,6 @@ createEditor( QWidget* parent, const QStyleOptionViewItem& option, QWidget* editor; QVariant myData = index.data( Qt::UserRole ); - // check for data types we need to handle ourselves - /* - if ( qVariantCanConvert< QColor >( myData ) ) - { - ColorItemEditor* colorEditor = new ColorItemEditor( parent ); - editor = colorEditor; - - QObject::connect( colorEditor, SIGNAL(confirmed()), this, SLOT(commit())); - } - else if ( qVariantCanConvert< DeleteCurveMode >( myData ) ) - { - DeleteCurveModeItemEditor* modeEditor = - new DeleteCurveModeItemEditor( parent ); - modeEditor->setMode( qVariantValue< DeleteCurveMode >( myData ) ); - editor = modeEditor; - - QObject::connect( modeEditor, SIGNAL( currentIndexChanged( int ) ), this, - SLOT( commit( ) ) ); - } - else - { // default handler - editor = QItemDelegate::createEditor( parent, option, index ); - }*/ - if ( myData.canConvert< QColor >() ) { ColorItemEditor* colorEditor = new ColorItemEditor( parent ); @@ -66,16 +40,6 @@ createEditor( QWidget* parent, const QStyleOptionViewItem& option, QObject::connect( colorEditor, SIGNAL(confirmed()), this, SLOT(commit())); } - else if ( myData.canConvert< DeleteCurveMode >() ) - { - DeleteCurveModeItemEditor* modeEditor = - new DeleteCurveModeItemEditor( parent ); - modeEditor->setMode( myData.value< DeleteCurveMode >() ); - editor = modeEditor; - - QObject::connect( modeEditor, SIGNAL( currentIndexChanged( int ) ), this, - SLOT( commit( ) ) ); - } else { // default handler editor = QItemDelegate::createEditor( parent, option, index ); @@ -98,15 +62,6 @@ void PropertyValueDelegate::setModelData( QWidget* editor, Qt::UserRole); return; } - DeleteCurveModeItemEditor* modeEditor = - qobject_cast(editor); - if (modeEditor) { - model->setData(index, DeleteCurveMode::ToString(modeEditor->mode()), - Qt::DisplayRole); - model->setData(index, QVariant::fromValue(modeEditor->mode()), - Qt::UserRole); - return; - } QItemDelegate::setModelData(editor, model, index); } @@ -119,17 +74,12 @@ bool PropertyValueDelegate::eventFilter( QObject* object, QEvent* event ) ColorItemEditor* colorEditor = qobject_cast(editor); if (colorEditor) return false; - DeleteCurveModeItemEditor* modeEditor = - qobject_cast(editor); - if (modeEditor) - return false; } return QItemDelegate::eventFilter( object, event ); } void PropertyValueDelegate::commit( ) { - // std::cout << "commit selection" << std::endl; QWidget* editor = qobject_cast< QWidget* >( sender( ) ); if ( editor ) { diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/QtMetaTypes.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/QtMetaTypes.h new file mode 100644 index 00000000000..bb8df8fd722 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/QtMetaTypes.h @@ -0,0 +1,20 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENET_DEMO_QT_METATYPES_H +#define ARRANGEMENET_DEMO_QT_METATYPES_H + +#include +#include + +Q_DECLARE_METATYPE(CGAL::Object) + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.cpp new file mode 100644 index 00000000000..d018a1b80c3 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "RationalCurveInputDialog.h" +#include "ui_RationalCurveInputDialog.h" + +RationalCurveInputDialog::RationalCurveInputDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::RationalCurveInputDialog) +{ + ui->setupUi(this); + setTabOrder(ui->numeratorLineEdit, ui->denominatorLineEdit); + ui->numeratorLineEdit->setFocus(); +} + +RationalCurveInputDialog::~RationalCurveInputDialog() +{ + delete ui; +} + +std::string RationalCurveInputDialog::getNumeratorText() +{ + return ui->numeratorLineEdit->text().toStdString(); +} + +std::string RationalCurveInputDialog::getDenominatorText() +{ + return ui->denominatorLineEdit->text().toStdString(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.h new file mode 100644 index 00000000000..86c20abea2b --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.h @@ -0,0 +1,38 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_RATIONAL_CURVE_INPUT_DIALOG_H +#define ARRANGEMENT_DEMO_RATIONAL_CURVE_INPUT_DIALOG_H + +#include + +namespace Ui +{ +class RationalCurveInputDialog; +} + +class RationalCurveInputDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RationalCurveInputDialog(QWidget *parent = 0); + ~RationalCurveInputDialog(); + std::string getNumeratorText(); + std::string getDenominatorText(); + Ui::RationalCurveInputDialog* getUi(){return this->ui;} + +private: + Ui::RationalCurveInputDialog *ui; +}; + +#endif // ALGEBRAICCURVEINPUTDIALOG_H + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.ui b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.ui new file mode 100644 index 00000000000..fe5e82a8bee --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalCurveInputDialog.ui @@ -0,0 +1,94 @@ + + + RationalCurveInputDialog + + + + 0 + 0 + 440 + 258 + + + + Dialog + + + + + + + + + + + + 1 + + + <html><head/><body><p>Enter a rational curve in the form:</p><p align="center">Numerator(x)<br/>y = ---------------------------------<br/>Denominator(x)</p><p>For example, to insert a curve with poles at {-5,0,5} enter:</p><p align="center"><span style=" color:#000000;">x^2 + x + 1<br/>y = ---------------------------------<br/>x(x-5)(x+5)</span></p></body></html> + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Numerator(x) + + + + + + + Denominator(x) + + + + + + + + + buttonBox + accepted() + RationalCurveInputDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + RationalCurveInputDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalTypes.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalTypes.h new file mode 100644 index 00000000000..8cbca1c1949 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/RationalTypes.h @@ -0,0 +1,40 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_RATIONAL_TYPES_H +#define ARRANGEMENT_DEMO_RATIONAL_TYPES_H + +#include +#include +#ifdef CGAL_USE_CORE + #include +#else + #include +#endif + +namespace demo_types +{ + +struct RationalTypes +{ +#ifdef CGAL_USE_CORE + typedef CORE::BigRat Rational; +#else + typedef CGAL::Exact_rational Rational; +#endif + + typedef CGAL::Cartesian Rat_kernel; + typedef CGAL::Point_2 Rat_point_2; +}; + +} // namespace demo_types + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.cpp index a5d51dad705..e608e750be6 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,33 +7,177 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "SplitEdgeCallback.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveInputMethods.h" +#include "PointSnapper.h" +#include "Utils/ConstructSegment.h" +#include "Utils/IntersectCurves.h" +#include "Utils/SplitAndMerge.h" -void SplitEdgeCallbackBase::setSnappingEnabled( bool b ) +#include +#include + +template +class SplitEdgeCallback : + public SplitEdgeCallbackBase, + public CGAL::Qt::CurveInputMethodCallback +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::Point_2 Point_2; + typedef typename CGAL::Qt::CurveInputMethod::Point_2 Input_point_2; + + SplitEdgeCallback(Arrangement* arr_, QObject* parent); + void setScene(QGraphicsScene* scene_) override; + void reset() override; + +protected: + void curveInputDoneEvent( + const std::vector& clickedPoints, + CGAL::Qt::CurveType type) override; + + void splitEdges(const Input_point_2& p1, const Input_point_2& p2); + + void setColor(QColor c) override; + QColor getColor() const override; + void setPointSnapper(PointSnapperBase*) override; + bool eventFilter(QObject* object, QEvent* event) override; + + Arrangement* arr; + CGAL::Qt::SegmentInputMethod segmentInputMethod; + Intersect_curves intersectCurves; + Split_edge edgeSplitter; +}; // class SplitEdgeCallback + +SplitEdgeCallbackBase::SplitEdgeCallbackBase(QObject* parent) : + CGAL::Qt::Callback(parent) { - this->snappingEnabled = b; } -void SplitEdgeCallbackBase::setSnapToGridEnabled( bool b ) +// msvc2015 doesn't play well with polymorphic lambdas +namespace { - this->snapToGridEnabled = b; +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new SplitEdgeCallback(arr, parent); + } + + SplitEdgeCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +SplitEdgeCallbackBase* SplitEdgeCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + SplitEdgeCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; } -void SplitEdgeCallbackBase::setColor( QColor c ) +template +SplitEdgeCallback::SplitEdgeCallback(Arrangement* arr_, QObject* parent) : + SplitEdgeCallbackBase(parent), arr(arr_), + intersectCurves(this->arr->traits()) { - this->color = c; + segmentInputMethod.setCallback(this); + this->setColor(::Qt::darkGray); } -QColor SplitEdgeCallbackBase::getColor( ) const +template +bool SplitEdgeCallback::eventFilter(QObject* object, QEvent* event) { - return this->color; + return segmentInputMethod.eventFilter(object, event); } -SplitEdgeCallbackBase::SplitEdgeCallbackBase( QObject* parent ) : - CGAL::Qt::Callback( parent ), - snappingEnabled( false ), - snapToGridEnabled( false ), - color( ::Qt::blue ) -{ } +template +void SplitEdgeCallback::setColor(QColor c) +{ + this->segmentInputMethod.setColor(c); +} + +template +QColor SplitEdgeCallback::getColor() const +{ + return this->segmentInputMethod.getColor(); +} + +template +void SplitEdgeCallback::setPointSnapper(PointSnapperBase* snapper_) +{ + this->segmentInputMethod.setPointSnapper(snapper_); +} + +template +void SplitEdgeCallback::setScene(QGraphicsScene* scene_) +{ + CGAL::Qt::Callback::setScene(scene_); + this->segmentInputMethod.setScene(scene_); +} + +template +void SplitEdgeCallback::reset() +{ + this->segmentInputMethod.reset(); +} + +template +void SplitEdgeCallback::curveInputDoneEvent( + const std::vector& clickedPoints, CGAL::Qt::CurveType) +{ + try + { + this->splitEdges(clickedPoints[0], clickedPoints[1]); + } + catch (const std::exception& ex) + { + std::cerr << ex.what() << '\n'; + std::cerr << __FILE__ << ':' << __LINE__ << '\n'; + return; + } +} + +template +void SplitEdgeCallback::splitEdges( + const Input_point_2& p1, const Input_point_2& p2) +{ + Construct_segment construct_segment; + + X_monotone_curve_2 splitCurve = + construct_segment(this->arr->traits(), p1, p2); + + for (auto hei = this->arr->halfedges_begin(); + hei != this->arr->halfedges_end(); ++hei) + { + X_monotone_curve_2 curve = hei->curve(); + std::vector intersection_points; + this->intersectCurves(splitCurve, curve, intersection_points); + + for (auto& pt_obj : intersection_points) + { + std::pair pt_pair; + if (CGAL::assign(pt_pair, pt_obj)) + { + Point_2 splitPoint = pt_pair.first; + this->edgeSplitter(this->arr, hei, splitPoint); + } + } + } + this->reset(); + Q_EMIT modelChanged(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.h index 47871586abb..9a93bd15e1d 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/SplitEdgeCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,343 +7,42 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef SPLIT_EDGE_CALLBACK_H #define SPLIT_EDGE_CALLBACK_H +#include #include "Callback.h" -#include -#include -#include -#include -#include -#include "CurveGraphicsItem.h" -#include "Utils.h" -#include "ISnappable.h" +class QGraphicsSceneMouseEvent; +class QGraphicsScene; +class QGraphicsLineItem; +class PointSnapperBase; +class QColor; -class SplitEdgeCallbackBase : public CGAL::Qt::Callback, public ISnappable +namespace demo_types { -public: - void setSnappingEnabled( bool b ); - void setSnapToGridEnabled( bool b ); - - virtual void setColor( QColor c ); - QColor getColor( ) const; - -protected: - SplitEdgeCallbackBase( QObject* parent ); - - bool snappingEnabled; - bool snapToGridEnabled; - QColor color; - -}; // SplitEdgeCallbackBase +enum class TraitsType : int; +} /** Handles splitting of arrangement curves selected from the scene. - - The template parameter is a CGAL::Arrangement_with_history_2 of some type. */ -template < class Arr_ > -class SplitEdgeCallback : public SplitEdgeCallbackBase +class SplitEdgeCallbackBase : public CGAL::Qt::Callback + { public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename Traits::Intersect_2 Intersect_2; - typedef typename Traits::Equal_2 Equal_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef typename ArrTraitsAdaptor< Traits >::Point_2 Point_2; - typedef typename ArrTraitsAdaptor< Traits >::CoordinateType CoordinateType; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::FT FT; + static SplitEdgeCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); - SplitEdgeCallback( Arrangement* arr_, QObject* parent ); - void setScene( QGraphicsScene* scene_ ); - virtual void setColor( QColor c ); - void reset( ); - - void slotModelChanged( ); + virtual void setColor(QColor c) = 0; + virtual QColor getColor() const = 0; + virtual void setPointSnapper(PointSnapperBase*) = 0; protected: - void mousePressEvent( QGraphicsSceneMouseEvent *event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent *event ); - - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent *event ); - template < class TTraits > - Point_2 snapPoint( QGraphicsSceneMouseEvent *event, TTraits traits ); - template < class CircularKernel > - Point_2 snapPoint( QGraphicsSceneMouseEvent* event, - CGAL::Arr_circular_arc_traits_2< CircularKernel > traits ); - - template < class TTraits > - void splitEdges( const Point_2& pt, TTraits traits ); - template < class CircularKernel > - void splitEdges( const Point_2& pt, - CGAL::Arr_circular_arc_traits_2< CircularKernel > traits ); - - template < class Coefficient_ > - void splitEdges( const Point_2& pt, - CGAL::Arr_algebraic_segment_traits_2 traits); - - template < class TTraits > - void updateGuide( const Point_2& pt, TTraits traits ); - - template < class CircularKernel > - void updateGuide( const Point_2& pt, - CGAL::Arr_circular_arc_traits_2< CircularKernel > traits ); - - Traits traits; - CGAL::Qt::Converter< Kernel > convert; - Arrangement* arr; - bool hasFirstPoint; - Point_2 p1; - Point_2 p2; - QGraphicsLineItem segmentGuide; - - Intersect_2 intersectCurves; - Equal_2 areEqual; - SnapToArrangementVertexStrategy< Arrangement > snapToVertexStrategy; - SnapToGridStrategy< typename Arrangement::Geometry_traits_2 > - snapToGridStrategy; -}; // class SplitEdgeCallback - -template < typename Arr_ > -SplitEdgeCallback< Arr_ >::SplitEdgeCallback( Arrangement* arr_, - QObject* parent ): - SplitEdgeCallbackBase( parent ), - arr( arr_ ), - hasFirstPoint( false ), - intersectCurves( this->traits.intersect_2_object( ) ), - areEqual( this->traits.equal_2_object( ) ) -{ - this->segmentGuide.setZValue( 100 ); - QPen pen = this->segmentGuide.pen( ); - pen.setColor( this->color ); - this->segmentGuide.setPen( pen ); - - this->snapToVertexStrategy.setArrangement( arr_ ); - - QObject::connect( this, SIGNAL( modelChanged( ) ), - this, SLOT( slotModelChanged( ) ) ); -} - -template < typename Arr_ > -void SplitEdgeCallback< Arr_ >::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; - this->snapToVertexStrategy.setScene( scene_ ); - this->snapToGridStrategy.setScene( scene_ ); - if ( this->scene ) - { - this->scene->addItem( &( this->segmentGuide ) ); - } -} - -template < typename Arr_ > -void SplitEdgeCallback< Arr_ >::setColor( QColor c ) -{ - this->color = c; - - QPen pen = this->segmentGuide.pen( ); - pen.setColor( c ); - this->segmentGuide.setPen( pen ); -} - -template < typename Arr_ > -void SplitEdgeCallback< Arr_ >::reset( ) -{ - this->hasFirstPoint = false; - this->segmentGuide.setLine( 0, 0, 0, 0 ); - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void SplitEdgeCallback< Arr_ >::slotModelChanged( ) -{ - this->segmentGuide.update( ); -} - -template < typename Arr_ > -void -SplitEdgeCallback< Arr_ >::mousePressEvent( QGraphicsSceneMouseEvent* event ) -{ - Point_2 clickedPoint = this->snapPoint( event ); - this->splitEdges( clickedPoint, Traits( ) ); -} - -template < typename Arr_ > -template < typename TTraits > -void SplitEdgeCallback< Arr_ >:: -splitEdges( const Point_2& clickedPoint, TTraits traits ) -{ - typename TTraits::Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = - traits.construct_x_monotone_curve_2_object( ); - if ( ! this->hasFirstPoint ) - { - this->p1 = clickedPoint; - this->hasFirstPoint = true; - } - else - { - this->p2 = clickedPoint; - X_monotone_curve_2 splitCurve = - construct_x_monotone_curve_2( this->p1, this->p2 ); - for ( Halfedge_iterator hei = this->arr->halfedges_begin( ); - hei != this->arr->halfedges_end( ); ++hei ) - { - X_monotone_curve_2 curve = hei->curve( ); - CGAL::Object res; - CGAL::Oneset_iterator< CGAL::Object > oi( res ); - this->intersectCurves( splitCurve, curve, oi ); - std::pair< Point_2, Multiplicity > pair; - if ( hei == this->arr->halfedges_end( ) ) - continue; - if ( CGAL::assign( pair, res ) ) - { - Point_2 splitPoint = pair.first; - if ( ( ! hei->source( )->is_at_open_boundary( ) && - this->areEqual( hei->source( )->point( ), splitPoint ) ) || - ( ! hei->target( )->is_at_open_boundary( ) && - this->areEqual( hei->target( )->point( ), splitPoint ) ) ) - { - continue; - } - this->arr->split_edge( hei, splitPoint ); - } - } - - this->reset( ); - } - - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -template < typename CircularKernel > -void SplitEdgeCallback< Arr_ >:: -splitEdges(const Point_2& /* clickedPoint */, - CGAL::Arr_circular_arc_traits_2< CircularKernel > /* traits */) -{ - // std::cout << "Circular arc split edges stub" << std::endl; -} - -template < typename Arr_ > -template < typename Coefficient_ > -void SplitEdgeCallback< Arr_ >:: -splitEdges(const Point_2& /* clickedPoint */, - CGAL::Arr_algebraic_segment_traits_2< Coefficient_ > /* traits */) -{ - // std::cout << "Algebraic segment split edges stub" << std::endl; -} - -template < typename Arr_ > -void -SplitEdgeCallback< Arr_ >::mouseMoveEvent( QGraphicsSceneMouseEvent* event ) -{ - Point_2 clickedPoint = this->snapPoint( event ); - this->updateGuide( clickedPoint, this->traits ); -} - -template < typename Arr_ > -template < typename TTraits > -void SplitEdgeCallback::updateGuide(const Point_2& clickedPoint, - TTraits /* traits */) -{ - if ( this->hasFirstPoint ) - { // provide visual feedback for where the split line is - Point_2 currentPoint = clickedPoint; - typename Kernel::Point_2 pt1( CGAL::to_double( this->p1.x( ) ), - CGAL::to_double( this->p1.y( ) ) ); - typename Kernel::Point_2 pt2( CGAL::to_double( currentPoint.x( ) ), - CGAL::to_double( currentPoint.y( ) ) ); - Segment_2 currentSegment( pt1, pt2 ); - QLineF qSegment = this->convert( currentSegment ); - this->segmentGuide.setLine( qSegment ); - Q_EMIT modelChanged( ); - } -} - -template < typename Arr_ > -template < typename CircularKernel > -void SplitEdgeCallback< Arr_ >:: -updateGuide(const Point_2& clickedPoint, - CGAL::Arr_circular_arc_traits_2< CircularKernel > /* traits */) -{ - if ( this->hasFirstPoint ) - { // provide visual feedback for where the split line is - Point_2 currentPoint = clickedPoint; - typename CircularKernel::Point_2 pt1( CGAL::to_double( this->p1.x( ) ), - CGAL::to_double( this->p1.y( ) ) ); - typename CircularKernel::Point_2 pt2( CGAL::to_double( currentPoint.x( ) ), - CGAL::to_double( currentPoint.y( ) ) ); - Segment_2 currentSegment( pt1, pt2 ); - QLineF qSegment = this->convert( currentSegment ); - this->segmentGuide.setLine( qSegment ); - Q_EMIT modelChanged( ); - } -} - -template < typename Arr_ > -typename SplitEdgeCallback< Arr_ >::Point_2 -SplitEdgeCallback< Arr_ >::snapPoint( QGraphicsSceneMouseEvent* event ) -{ - return this->snapPoint( event, Traits( ) ); -} - -template < typename Arr_ > -template < typename TTraits > -typename SplitEdgeCallback< Arr_ >::Point_2 -SplitEdgeCallback::snapPoint(QGraphicsSceneMouseEvent* event, - TTraits /* traits */) -{ - if ( this->snapToGridEnabled ) - { - return this->snapToGridStrategy.snapPoint( event ); - } - if ( this->snappingEnabled ) - { - return this->snapToVertexStrategy.snapPoint( event ); - } - else - { // fallback "analog" selection - typename Kernel::Point_2 pt = this->convert( event->scenePos( ) ); - CoordinateType x( pt.x( ) ); - CoordinateType y( pt.y( ) ); - return Point_2( x, y ); - } -} - -template < typename Arr_ > -template < typename CircularKernel > -typename SplitEdgeCallback< Arr_ >::Point_2 SplitEdgeCallback< Arr_ >:: -snapPoint(QGraphicsSceneMouseEvent* event, - CGAL::Arr_circular_arc_traits_2 /* traits */) -{ - if ( this->snapToGridEnabled ) - { - return this->snapToGridStrategy.snapPoint( event ); - } - if ( this->snappingEnabled ) - { - return this->snapToVertexStrategy.snapPoint( event ); - } - else - { // fallback "analog" selection - typename Kernel::Point_2 pt = this->convert( event->scenePos( ) ); - return Point_2( pt ); - } -} + SplitEdgeCallbackBase(QObject* parent); +}; // SplitEdgeCallbackBase #endif // SPLIT_EDGE_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.cpp deleted file mode 100644 index 3ba0a03dd04..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#include "Utils.h" -#include "ArrangementTypes.h" diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.h deleted file mode 100644 index 9bddc6fb8be..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils.h +++ /dev/null @@ -1,1620 +0,0 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org). -// -// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Alex Tsui - -#ifndef CGAL_ARRANGEMENTS_DEMO_UTILS_H -#define CGAL_ARRANGEMENTS_DEMO_UTILS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ArrangementTypes.h" - -class QGraphicsScene; - -class QGraphicsSceneMixin -{ -public: - /*! Costructor */ - QGraphicsSceneMixin( ) : scene( 0 ) { } - - /*! Destructor (virtual) */ - virtual ~QGraphicsSceneMixin() {} - - virtual void setScene( QGraphicsScene* scene_ ) { this->scene = scene_; } - - virtual QGraphicsScene* getScene( ) const { return this->scene; } - - virtual QRectF viewportRect( ) const - { - QRectF res; - if ( this->scene == NULL ) - { - return res; - } - - QList< QGraphicsView* > views = this->scene->views( ); - if ( views.size( ) == 0 ) - { - return res; - } - // assumes the first view is the right one - QGraphicsView* viewport = views.first( ); - QPointF p1 = viewport->mapToScene( 0, 0 ); - QPointF p2 = viewport->mapToScene(viewport->width(), viewport->height()); - - double xmin = (std::min)(p1.x(), p2.x()); - double xmax = (std::max)(p1.x(), p2.x()); - double ymin = (std::min)(p1.y(), p2.y()); - double ymax = (std::max)(p1.y(), p2.y()); - - res = QRectF( QPointF( xmin, ymin ), QPointF( xmax, ymax ) ); - - return res; - } - - QPoint fromScene( QPointF p, bool* ok = 0 ) - { - QPoint res; - if ( this->scene == NULL ) - { - if ( ok ) { *ok = false; } - return res; - } - QList< QGraphicsView* > views = this->scene->views( ); - if ( views.size( ) == 0 ) - { - if ( ok ) { *ok = false; } - return res; - } - - // assumes the first view is the right one - QGraphicsView* viewport = views.first( ); - - if ( ok ) { *ok = true; } - res = viewport->mapFromScene( p ); - return res; - } - - QPointF toScene( QPoint p, bool* ok = 0 ) - { - QPointF res; - if ( this->scene == NULL ) - { - if ( ok ) { *ok = false; } - return res; - } - QList< QGraphicsView* > views = this->scene->views( ); - if ( views.size( ) == 0 ) - { - if ( ok ) { *ok = false; } - return res; - } - - // assumes the first view is the right one - QGraphicsView* viewport = views.first( ); - - if ( ok ) { *ok = true; } - res = viewport->mapToScene( p ); - return res; - } - - int fromScene( double d, bool* ok = 0 ) - { - QPointF p( d, 0 ); - QPoint pp = this->fromScene( p, ok ); - return pp.x( ); - } - - double toScene( int i, bool* ok = 0 ) - { - QPoint p( i, 0 ); - QPointF pp = this->toScene( p, ok ); - return pp.x( ); - } - -protected: // fields - QGraphicsScene* scene; -}; - -BOOST_MPL_HAS_XXX_TRAIT_DEF( Approximate_2 ) - -template < class Arr_, bool b = has_Approximate_2< Arr_ >::value > -struct Supports_landmarks -{ - typedef CGAL::Boolean_tag< b > Tag; - struct LandmarksType { }; -}; - -template < class Arr_ > -struct Supports_landmarks< Arr_, true > -{ - typedef CGAL::Tag_true Tag; - typedef CGAL::Arr_landmarks_point_location< Arr_ > LandmarksType; -}; - -/** - Support for new ArrTraits should specify types: - - * Kernel - a not-necessarily-exact kernel to represent the arrangement - graphically. We'll use the Point_2 type provided by this kernel for - computing distances - * Point_2 - the point type used in the particular arrangement - * CoordinateType - the coordinate type used by the point type - */ -template < class ArrTraits > -class ArrTraitsAdaptor -{ }; - -template < class Kernel_ > -class ArrTraitsAdaptor< CGAL::Arr_segment_traits_2< Kernel_ > > -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_segment_traits_2< Kernel > ArrTraits; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::FT CoordinateType; -}; - -template < class Kernel_ > -class ArrTraitsAdaptor< CGAL::Arr_linear_traits_2< Kernel_ > > -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_linear_traits_2< Kernel > ArrTraits; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::FT CoordinateType; -}; - -template < class SegmentTraits > -class ArrTraitsAdaptor< CGAL::Arr_polyline_traits_2< SegmentTraits > > -{ -public: - typedef CGAL::Arr_polyline_traits_2< SegmentTraits > ArrTraits; - typedef typename SegmentTraits::Kernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::FT CoordinateType; -}; - -template < class CircularKernel > -class ArrTraitsAdaptor< CGAL::Arr_circular_arc_traits_2< CircularKernel > > -{ -public: - typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > ArrTraits; - typedef CircularKernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::Root_of_2 CoordinateType; -}; - -template < class RatKernel, class AlgKernel, class NtTraits > -class ArrTraitsAdaptor< CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, - NtTraits > > -{ -public: - typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > ArrTraits; - typedef AlgKernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::FT CoordinateType; -}; - -template < class Coefficient_ > -class ArrTraitsAdaptor< CGAL::Arr_algebraic_segment_traits_2< Coefficient_ > > -{ -public: - typedef Coefficient_ Coefficient; - typedef typename CGAL::Arr_algebraic_segment_traits_2 - ArrTraits; - typedef typename ArrTraits::Point_2 Point_2; // CKvA_2 - typedef typename ArrTraits::Algebraic_real_1 CoordinateType; - typedef CGAL::Cartesian< typename ArrTraits::Bound > Kernel; - //typedef typename ArrTraits::CKvA_2 Kernel; -}; - -template < class ArrTraits > -class Compute_squared_distance_2_base : public QGraphicsSceneMixin -{ -public: - typedef CGAL::Cartesian< double > InexactKernel; - -public: - // ctors - Compute_squared_distance_2_base( ) { } - -public: // methods - - template < class T1, class T2 > - double operator() ( const T1& t1, const T2& t2 ) - { - return this->squaredDistance( t1, t2 ); - } - -protected: // fields - typename Kernel::Compute_squared_distance_2 squared_distance; - InexactKernel::Compute_squared_distance_2 squaredDistance; -}; - -template < class ArrTraits > -class Compute_squared_distance_2 : - public Compute_squared_distance_2_base< ArrTraits > -{ }; - -template < class Kernel_ > -class Compute_squared_distance_2< CGAL::Arr_segment_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_segment_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const - { - Point_2 p1 = c.source( ); - Point_2 p2 = c.target( ); - Segment_2 seg( p1, p2 ); - - return CGAL::to_double( this->squared_distance( p, seg ) ); - } -}; - -template < class Kernel_ > -class Compute_squared_distance_2< CGAL::Arr_linear_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_linear_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Ray_2 Ray_2; - typedef typename Kernel::Line_2 Line_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const - { - Segment_2 seg; - Ray_2 ray; - Line_2 line; - FT res; - if ( c.is_segment( ) ) - { - seg = c.segment( ); - res = this->squared_distance( p, seg ); - } - else if ( c.is_ray( ) ) - { - ray = c.ray( ); - res = this->squared_distance( p, ray ); - } - else // ( c.is_line( ) ) - { - line = c.line( ); - res = this->squared_distance( p, line ); - } - return CGAL::to_double( res ); - } -}; - -template < class Kernel_ > -class Compute_squared_distance_2< CGAL::Arr_polyline_traits_2< Kernel_ > > : - public Compute_squared_distance_2_base > -{ -public: - typedef Kernel_ Kernel; - typedef CGAL::Arr_polyline_traits_2< Kernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Curve_2::Subcurve_const_iterator Seg_const_it; - - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const - { - Seg_const_it seg_it_s = c.subcurves_begin(); - - bool first = true; - FT min_dist = 0; - - while (seg_it_s != c.subcurves_end()) - { - Segment_2 seg = *seg_it_s; - FT dist = this->squared_distance( p, seg ); - - if ( first || dist < min_dist ) - { - first = false; - min_dist = dist; - } - seg_it_s++; - } - - return CGAL::to_double( min_dist ); - } -}; - -template < class CircularKernel > -class Compute_squared_distance_2< CGAL::Arr_circular_arc_traits_2< - CircularKernel > > : - public Compute_squared_distance_2_base< CGAL::Arr_circular_arc_traits_2< - CircularKernel > > -{ -public: // typedefs - typedef CircularKernel Kernel; - typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - typedef typename Traits::Point_2 Point_2; - typedef typename Traits::Point_2 Arc_point_2; - typedef typename Kernel::Point_2 Non_arc_point_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Kernel::FT FT; - -public: // methods - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) - { - // TODO: implement it correctly - Non_arc_point_2 center = c.center( ); - Non_arc_point_2 pp( CGAL::to_double(p.x()), CGAL::to_double(p.y()) ); - FT res = CGAL::squared_distance( pp, center ); - return CGAL::to_double( res ); - } -}; - -template < class RatKernel, class AlgKernel, class NtTraits > -class Compute_squared_distance_2< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > : - public Compute_squared_distance_2_base< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > -{ -public: - typedef AlgKernel Kernel; - typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > Traits; - typedef Compute_squared_distance_2_base< Traits > Superclass; - // _Conic_point_2< AlgKernel > : public AlgKernel::Point_2 - typedef typename Traits::Point_2 Conic_point_2; - typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Traits::Curve_2 Curve_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - -public: // methods - double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const - { - // Get the co-ordinates of the curve's source and target. - // double sx = CGAL::to_double( c.source( ).x( ) ); - // double sy = CGAL::to_double( c.source( ).y( ) ); - // double tx = CGAL::to_double( c.target( ).x( ) ); - // double ty = CGAL::to_double( c.target( ).y( ) ); - - if ( c.orientation( ) == CGAL::COLLINEAR ) - { - Point_2 ps = c.source( ); - Point_2 pt = c.target( ); - Segment_2 seg( ps, pt ); - - FT res = CGAL::squared_distance( p, seg ); - return CGAL::to_double( res ); - } - else - { - // If the curve is monotone, than its source and its target has the - // extreme x co-ordinates on this curve. - // bool is_source_left = (sx < tx); - //int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); - //int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); - //double prev_x = is_source_left ? sx : tx; - //double prev_y = is_source_left ? sy : ty; - //double curr_x, curr_y; - //int x; - //Arr_conic_point_2 px; - - bool first = true; - FT min_dist( 100000000 ); - // AlgKernel ker; - - int n = 100; - if ( this->scene != NULL && this->scene->views( ).size( ) != 0 ) - { // use the scene to approximate the resolution of the curve - QGraphicsView* view = this->scene->views( ).first( ); - CGAL::Bbox_2 bb = c.bbox( ); // assumes bounded curve - int xmin = view->mapFromScene( bb.xmin( ), bb.ymin( ) ).x( ); - int xmax = view->mapFromScene( bb.xmax( ), bb.ymin( ) ).x( ); - n = xmax - xmin; - if ( n < 2 ) - { - n = 2; - } - } - - std::pair* app_pts = - new std::pair< double, double >[ n + 1 ]; - std::pair* end_pts = c.polyline_approximation(n, app_pts); - std::pair* p_curr = app_pts; - std::pair* p_next = p_curr + 1; - do - { - Point_2 p1( p_curr->first, p_curr->second ); - Point_2 p2( p_next->first, p_next->second ); - Segment_2 seg( p1, p2 ); - - FT dist = CGAL::squared_distance( p, seg ); - if ( first || dist < min_dist ) - { - first = false; - min_dist = dist; - } - - p_curr++; - p_next++; - } while ( p_next != end_pts ); - - return CGAL::to_double( min_dist ); - } - } -}; - -template < class Coefficient_ > -class Compute_squared_distance_2< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > : - public Compute_squared_distance_2_base< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > -{ -public: - typedef Coefficient_ Coefficient; - typedef CGAL::Arr_algebraic_segment_traits_2 - Traits; - typedef typename Traits::Bound FT; // unused - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - -public: - double operator()(const Point_2& /* p */, - const X_monotone_curve_2& /* c */) const - { - double res = 0.0; - return res; - } -}; - -template < class ArrTraits > -class Arr_compute_y_at_x_2 : public QGraphicsSceneMixin -{ -public: - typedef ArrTraits Traits; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename ArrTraitsAdaptor< Traits >::CoordinateType CoordinateType; - // typedef typename Kernel::FT FT; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Line_2 Line_2; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef typename Traits::Intersect_2 Intersect_2; - typedef std::pair< typename Traits::Point_2, Multiplicity > - IntersectionResult; - - /*! Constructor */ - Arr_compute_y_at_x_2( ) : - intersectCurves( this->traits.intersect_2_object( ) ) - { } - - /*! Destructor (virtual) */ - virtual ~Arr_compute_y_at_x_2() {} - - CoordinateType operator() ( const X_monotone_curve_2& curve, - const CoordinateType& x ) - { - typename Traits::Left_side_category category; - return this->operator()( curve, x, this->traits, category ); - } - - double approx( const X_monotone_curve_2& curve, const CoordinateType& x ) - { - return CGAL::to_double( (*this)( curve, x ) ); - } - -protected: - template < class TTraits > - CoordinateType operator() ( const X_monotone_curve_2& curve, - const CoordinateType& x, TTraits traits_, - CGAL::Arr_oblivious_side_tag ) - { - typedef typename TTraits::Construct_x_monotone_curve_2 - Construct_x_monotone_curve_2; - Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = - traits_.construct_x_monotone_curve_2_object( ); - CoordinateType res( 0 ); - CGAL::Bbox_2 clipRect = curve.bbox( ); - Point_2 p1c1( x, CoordinateType( clipRect.ymin( ) - 1 ) ); // clicked point - // upper bounding box - Point_2 p2c1( x, CoordinateType( clipRect.ymax( ) + 1 ) ); - - const X_monotone_curve_2 verticalLine = - construct_x_monotone_curve_2( p1c1, p2c1 ); - CGAL::Object o; - CGAL::Oneset_iterator< CGAL::Object > oi( o ); - - this->intersectCurves( curve, verticalLine, oi ); - - IntersectionResult pair; - if ( CGAL::assign( pair, o ) ) - { - Point_2 pt = pair.first; - res = pt.y( ); - } - return res; - } - - template < class TTraits > - CoordinateType operator() ( const X_monotone_curve_2& curve, - const CoordinateType& x, TTraits traits_, - CGAL::Arr_open_side_tag ) - { - typename TTraits::Construct_x_monotone_curve_2 - construct_x_monotone_curve_2 = - traits_.construct_x_monotone_curve_2_object( ); - CoordinateType res( 0 ); - // QRectF clipRect = this->viewportRect( ); - Line_2 line = curve.supporting_line( ); - // FIXME: get a better bounding box for an unbounded segment - Point_2 p1c1( x, CoordinateType( -10000000 ) ); // clicked point - Point_2 p2c1( x, CoordinateType( 10000000 ) ); // upper bounding box - - const X_monotone_curve_2 verticalLine = - construct_x_monotone_curve_2( p1c1, p2c1 ); - CGAL::Object o; - CGAL::Oneset_iterator< CGAL::Object > oi( o ); - - this->intersectCurves( curve, verticalLine, oi ); - - IntersectionResult pair; - if ( CGAL::assign( pair, o ) ) - { - Point_2 pt = pair.first; - res = pt.y( ); - } - return res; - } - -protected: - Traits traits; - Intersect_2 intersectCurves; -}; - -template < class CircularKernel > -class Arr_compute_y_at_x_2< CGAL::Arr_circular_arc_traits_2 > : - public QGraphicsSceneMixin -{ -public: - typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > Traits; - typedef CircularKernel Kernel; - typedef typename Kernel::FT FT; - typedef typename Kernel::Root_of_2 Root_of_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Traits::Point_2 Arc_point_2; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::Line_arc_2 Line_arc_2; - // Circular_arc_2 - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Intersect_2 Intersect_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef std::pair< typename Traits::Point_2, Multiplicity > - IntersectionResult; - - /*! Constructor */ - Arr_compute_y_at_x_2( ) : - intersectCurves( this->traits.intersect_2_object( ) ) - { } - - /*! Destructor (virtual) */ - virtual ~Arr_compute_y_at_x_2() {} - - Root_of_2 operator() ( const X_monotone_curve_2& curve, const FT& x ) - { - Root_of_2 res( 0 ); - CGAL::Bbox_2 clipRect = curve.bbox( ); - Point_2 p1c1( x, FT( clipRect.ymin( ) - 1 ) ); // clicked point - Point_2 p2c1( x, FT( clipRect.ymax( ) + 1 ) ); // upper bounding box - Line_arc_2 verticalLine( Segment_2( p1c1, p2c1 ) ); - - CGAL::Object o; - CGAL::Oneset_iterator< CGAL::Object > oi( o ); - - this->intersectCurves( curve, verticalLine, oi ); - - IntersectionResult pair; - if ( CGAL::assign( pair, o ) ) - { - Arc_point_2 pt = pair.first; - res = pt.y( ); - } - return res; - } - - double approx( const X_monotone_curve_2& curve, const FT& x ) - { - return CGAL::to_double( (*this)( curve, x ) ); - } - - // FIXME: inexact projection - Root_of_2 operator() ( const X_monotone_curve_2& curve, const Root_of_2& x ) - { - FT approx( CGAL::to_double( x ) ); - return this->operator()( curve, approx ); - } - - double approx( const X_monotone_curve_2& curve, const Root_of_2& x ) - { - return CGAL::to_double( (*this)( curve, x ) ); - } - -protected: - Traits traits; - Intersect_2 intersectCurves; -}; - -template < class Coefficient_ > -class Arr_compute_y_at_x_2< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > : public QGraphicsSceneMixin -{ -public: - typedef Coefficient_ Coefficient; - typedef CGAL::Arr_algebraic_segment_traits_2< Coefficient > Traits; - typedef typename Traits::Algebraic_real_1 CoordinateType; - typedef typename Traits::Point_2 Point_2; - typedef typename Traits::Intersect_2 Intersect_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - - CoordinateType operator() ( const X_monotone_curve_2& curve, - const CoordinateType& x ) - { - CGAL::Object o; - CGAL::Oneset_iterator< CGAL::Object > oi( o ); - Intersect_2 intersect = traits.intersect_2_object( ); - X_monotone_curve_2 c2 = this->makeVerticalLine( x ); - intersect( curve, c2, oi ); - std::pair< Point_2, Multiplicity > res; - if ( CGAL::assign( res, o ) ) // TODO: handle failure case - { - Point_2 p = res.first; - // std::cout << "approx y: " << p.to_double( ).second << std::endl; - CoordinateType coord = p.y( ); - return coord; - } - else - { - std::cout << "Warning: vertical projection failed" << std::endl; - return CoordinateType( 0 ); - } - } - - double approx( const X_monotone_curve_2& curve, const CoordinateType& x ) - { - CGAL::Object o; - CGAL::Oneset_iterator< CGAL::Object > oi( o ); - Intersect_2 intersect = traits.intersect_2_object( ); - X_monotone_curve_2 c2 = this->makeVerticalLine( x ); - intersect( curve, c2, oi ); - std::pair< Point_2, Multiplicity > res; - if ( CGAL::assign( res, o ) ) // TODO: handle failure case - { - Point_2 p = res.first; - std::pair< double, double > tmp = p.to_double(); - return tmp.second; - } - else - { - std::cout << "Warning: vertical projection failed" << std::endl; - return 0; - } - } - -protected: - X_monotone_curve_2 makeVerticalLine( const CoordinateType& x ) - { - typename Traits::Construct_point_2 constructPoint = - traits.construct_point_2_object( ); - typename Traits::Construct_x_monotone_segment_2 constructSegment = - traits.construct_x_monotone_segment_2_object( ); - - std::vector< X_monotone_curve_2 > curves; - Point_2 p1 = constructPoint( x, CoordinateType( -1000000 ) ); - Point_2 p2 = constructPoint( x, CoordinateType( +1000000 ) ); - constructSegment( p1, p2, std::back_inserter( curves ) ); - return curves[ 0 ]; // by construction, there is one curve in curves - } - Traits traits; -}; - -#undef SUBCURVE_1 - -// TODO: Make Construct_x_monotone_subcurve_2 more generic -template < class ArrTraits > -class Construct_x_monotone_subcurve_2 -{ -public: - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraits::Split_2 Split_2; - typedef typename ArrTraits::Intersect_2 Intersect_2; - typedef typename ArrTraits::Multiplicity Multiplicity; - typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; - typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; - typedef typename ArrTraits::Compare_x_2 Compare_x_2; - typedef typename Kernel::FT FT; - typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType - CoordinateType; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::Point_2 Kernel_point_2; - //typedef typename Kernel::Line_2 Line_2; - //typedef typename Kernel::Compute_y_at_x_2 Compute_y_at_x_2; - - Construct_x_monotone_subcurve_2( ): - intersect_2( this->traits.intersect_2_object( ) ), - split_2( this->traits.split_2_object( ) ), - compare_x_2( this->traits.compare_x_2_object( ) ), - construct_min_vertex_2( this->traits.construct_min_vertex_2_object( ) ), - construct_max_vertex_2( this->traits.construct_max_vertex_2_object( ) ) - { } - - /* - Return the subcurve of curve bracketed by pLeft and pRight. - - We assume pLeft and pRight don't lie on the curve and always do a vertical - projection. - */ - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const Point_2& pLeft, const Point_2& pRight ) - { - Point_2 pMin = this->construct_min_vertex_2( curve ); - Point_2 pMax = this->construct_max_vertex_2( curve ); - X_monotone_curve_2 subcurve; - X_monotone_curve_2 unusedTrimmings; - X_monotone_curve_2 finalSubcurve; - if ( this->compare_x_2( pLeft, pMin ) == CGAL::LARGER ) - { - CoordinateType y1 = this->compute_y_at_x( curve, pLeft.x( ) ); - Point_2 splitPoint( pLeft.x( ), y1 ); - this->split_2( curve, splitPoint, unusedTrimmings, subcurve ); - } - else - { - subcurve = curve; - } - - if ( this->compare_x_2( pRight, pMax ) == CGAL::SMALLER ) - { - CoordinateType y2 = this->compute_y_at_x( subcurve, pRight.x( ) ); - Point_2 splitPoint( pRight.x( ), y2 ); - this->split_2( subcurve, splitPoint, finalSubcurve, unusedTrimmings ); - } - else - { - finalSubcurve = subcurve; - } - - return finalSubcurve; - } - -protected: - ArrTraits traits; - Intersect_2 intersect_2; - Split_2 split_2; - Compare_x_2 compare_x_2; - Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; - Construct_min_vertex_2 construct_min_vertex_2; - Construct_max_vertex_2 construct_max_vertex_2; -}; // class Construct_x_monotone_subcurve_2 - -template < class CircularKernel > -class Construct_x_monotone_subcurve_2< CGAL::Arr_circular_arc_traits_2< - CircularKernel > > -{ -public: - typedef CGAL::Arr_circular_arc_traits_2 ArrTraits; - typedef typename ArrTraits::Intersect_2 Intersect_2; - typedef typename ArrTraits::Split_2 Split_2; - typedef typename ArrTraits::Compare_x_2 Compare_x_2; - typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; - typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename CircularKernel::Point_2 Non_arc_point_2; - typedef typename ArrTraits::Point_2 Arc_point_2; - typedef typename CircularKernel::FT FT; - typedef typename CircularKernel::Root_of_2 Root_of_2; - typedef typename CircularKernel::Root_for_circles_2_2 Root_for_circles_2_2; - -public: - Construct_x_monotone_subcurve_2( ): - intersect_2( this->traits.intersect_2_object( ) ), - split_2( this->traits.split_2_object( ) ), - compare_x_2( this->traits.compare_x_2_object( ) ), - construct_min_vertex_2( this->traits.construct_min_vertex_2_object( ) ), - construct_max_vertex_2( this->traits.construct_max_vertex_2_object( ) ) - { } - - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const Arc_point_2& pLeft, - const Arc_point_2& pRight ) - { - Arc_point_2 pMin = this->construct_min_vertex_2( curve ); - Arc_point_2 pMax = this->construct_max_vertex_2( curve ); - X_monotone_curve_2 subcurve; - X_monotone_curve_2 unusedTrimmings; - X_monotone_curve_2 finalSubcurve; - if ( this->compare_x_2( pLeft, pMin ) == CGAL::LARGER ) - { - Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; - FT x_approx( CGAL::to_double( pLeft.x( ) ) ); - Root_of_2 y1 = compute_y_at_x( curve, x_approx ); - Root_for_circles_2_2 intersectionPoint( x_approx, y1 ); - Arc_point_2 splitPoint( intersectionPoint ); - this->split_2( curve, splitPoint, unusedTrimmings, subcurve ); - } - else - { - subcurve = curve; - } - - if ( this->compare_x_2( pRight, pMax ) == CGAL::SMALLER ) - { - Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; - FT x_approx( CGAL::to_double( pRight.x( ) ) ); - Root_of_2 y2 = compute_y_at_x( subcurve, x_approx ); - Root_for_circles_2_2 intersectionPoint( x_approx, y2 ); - Arc_point_2 splitPoint( intersectionPoint ); - this->split_2( subcurve, splitPoint, finalSubcurve, unusedTrimmings ); - } - else - { - finalSubcurve = subcurve; - } - - return finalSubcurve; - } - -protected: - ArrTraits traits; - Intersect_2 intersect_2; - Split_2 split_2; - Compare_x_2 compare_x_2; - Construct_min_vertex_2 construct_min_vertex_2; - Construct_max_vertex_2 construct_max_vertex_2; -}; - -/* - * This specialization for conic traits makes use of X_monotone_curve_2::trim, - * which is not necessarily available. - */ -template < class RatKernel, class AlgKernel, class NtTraits > -class Construct_x_monotone_subcurve_2< CGAL::Arr_conic_traits_2< RatKernel, - AlgKernel, - NtTraits > > -{ -public: - typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > ArrTraits; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename AlgKernel::Point_2 Point_2; - - /* - Return the subcurve of curve bracketed by pLeft and pRight. - */ - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const Point_2& pLeft, const Point_2& pRight ) - { - // find the points on the curve - Point_2 left = curve.point_at_x( pLeft ); - Point_2 right = curve.point_at_x( pRight ); - - // make sure the points are oriented in the direction that the curve is - // going - AlgKernel ker; - if (! (((curve.is_directed_right( )) && - ker.compare_xy_2_object() ( left, right ) == CGAL::SMALLER) || - ((! curve.is_directed_right( )) && - ker.compare_xy_2_object() ( left, right ) == CGAL::LARGER))) - { - Point_2 tmp = left; - left = right; - right = tmp; - } - - X_monotone_curve_2 res = curve.trim( left, right ); - return res; - } -}; // class Construct_x_monotone_subcurve_2 for Arr_conic_traits_2 - -template < class Kernel_ > -class Construct_x_monotone_subcurve_2< CGAL::Arr_linear_traits_2< Kernel_ > > -{ -public: // typedefs - typedef CGAL::Arr_linear_traits_2< Kernel_ > ArrTraits; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef Kernel_ Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - -public: // methods - // curve can be unbounded. if curve is unbounded to the left, - // pLeft is a point on the left edge of viewport. - X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, - const Point_2& pLeft, const Point_2& pRight ) - { - if ( curve.is_segment( ) ) - { - Segment_2 subsegment = - this->constructSubsegment( curve.segment( ), pLeft, pRight ); - return X_monotone_curve_2( subsegment ); - } - else if ( curve.is_ray( ) ) - { - - } - return curve; - } - -protected: - Construct_x_monotone_subcurve_2< CGAL::Arr_segment_traits_2< Kernel_ > > - constructSubsegment; -}; - -template < class Coefficient_ > -class Construct_x_monotone_subcurve_2< CGAL::Arr_algebraic_segment_traits_2< - Coefficient_ > > -{ -public: // typedefs - typedef Coefficient_ Coefficient; - typedef CGAL::Arr_algebraic_segment_traits_2< Coefficient > ArrTraits; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - //typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Segment_2 Segment_2; - -public: // methods - // curve can be unbounded. if curve is unbounded to the left, pLeft is a - // point on the left edge of viewport. - X_monotone_curve_2 operator()(const X_monotone_curve_2& curve, - const Point_2& /* pLeft */, - const Point_2& /* pRight */) - { - // TODO: trim the algebraic curve - return curve; - } - -protected: -}; - -// FIXME: return Traits::Point_2 instead of Kernel::Point_2 -template < class ArrTraits > -class SnapStrategy : public QGraphicsSceneMixin -{ -public: - //typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - - virtual Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) = 0; - -protected: - SnapStrategy( QGraphicsScene* scene_ ); -}; // class SnapStrategy - -template < class ArrTraits > -SnapStrategy< ArrTraits >::SnapStrategy( QGraphicsScene* scene_ ) -{ - this->scene = scene_; -} - -template < class ArrTraits > -class SnapToGridStrategy : public SnapStrategy< ArrTraits > -{ -public: - typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; - typedef typename ArrTraits::Point_2 Point_2; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef SnapStrategy< ArrTraits > Superclass; - - /*! Constructors */ - SnapToGridStrategy( ) : - Superclass( NULL ), - gridSize( 50 ) - { } - - SnapToGridStrategy( QGraphicsScene* scene ) : - Superclass( scene ), - gridSize( 50 ) - { } - - /*! Destructors (virtual) */ - ~SnapToGridStrategy() {} - - Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - return this->snapPoint( event, ArrTraits( ) ); - } - - template < class TTraits > - Point_2 snapPoint(QGraphicsSceneMouseEvent* event, TTraits /* traits */) - { - QPointF clickedPoint = event->scenePos( ); - QRectF viewportRect = this->viewportRect( ); - if ( viewportRect == QRectF( ) ) - { // fallback case; we usually shouldn't end up here - Kernel_point_2 res = this->convert( event->scenePos( ) ); - return Point_2( CGAL::to_double(res.x( )), CGAL::to_double(res.y()) ); - } - - qreal d( this->gridSize / 2.0 ); - int left = int( viewportRect.left( ) ) - - (int( viewportRect.left( ) ) % this->gridSize); - int right = int( viewportRect.right( ) ) + - (this->gridSize - int( viewportRect.right( ) ) % this->gridSize); - int x = int(clickedPoint.x( )); - int y = int(clickedPoint.y( )); - for ( int i = left - this->gridSize; i <= right; i += this->gridSize ) - { - if ( i - d <= clickedPoint.x( ) && clickedPoint.x( ) <= i + d ) - { - x = i; - break; - } - } - int top = int( viewportRect.top( ) ) - - (int( viewportRect.top( ) ) % this->gridSize); - int bottom = int( viewportRect.bottom( ) ) + - (this->gridSize - int( viewportRect.bottom( ) ) % this->gridSize); - for ( int i = top - this->gridSize; i <= bottom; i += this->gridSize ) - { - if ( i - d <= clickedPoint.y( ) && clickedPoint.y( ) <= i + d ) - { - y = i; - break; - } - } - //return this->convert( QPointF( x, y ) ); - Point_2 res( x, y ); - return res; - } - - template < class CircularKernel > - Point_2 snapPoint(QGraphicsSceneMouseEvent* event, - CGAL::Arr_circular_arc_traits_2 - /* traits */) - { - QPointF clickedPoint = event->scenePos( ); - QRectF viewportRect = this->viewportRect( ); - if ( viewportRect == QRectF( ) ) - { - Kernel_point_2 res = this->convert( event->scenePos( ) ); - return Point_2( res ); - } - - qreal d( this->gridSize / 2.0 ); - int left = int( viewportRect.left( ) ) - - (int( viewportRect.left( ) ) % this->gridSize); - int right = int( viewportRect.right( ) ) + - (this->gridSize - int( viewportRect.right( ) ) % this->gridSize); - int x = int(clickedPoint.x( )); - int y = int(clickedPoint.y( )); - for ( int i = left - this->gridSize; i <= right; i += this->gridSize ) - { - if ( i - d <= clickedPoint.x( ) && clickedPoint.x( ) <= i + d ) - { - x = i; - break; - } - } - int top = int( viewportRect.top( ) ) - - (int( viewportRect.top( ) ) % this->gridSize); - int bottom = int( viewportRect.bottom( ) ) + - (this->gridSize - int( viewportRect.bottom( ) ) % this->gridSize); - for ( int i = top - this->gridSize; i <= bottom; i += this->gridSize ) - { - if ( i - d <= clickedPoint.y( ) && clickedPoint.y( ) <= i + d ) - { - y = i; - break; - } - } - //return this->convert( QPointF( x, y ) ); - Kernel_point_2 res( x, y ); - return Point_2( res ); - } - - void setGridSize( int size ) - { - this->gridSize = size; - } - -protected: - int gridSize; - CGAL::Qt::Converter< Kernel > convert; -}; // class SnapToGridStrategy - -template < class Arr_ > -class SnapToArrangementVertexStrategy: - public SnapStrategy< typename Arr_::Geometry_traits_2 > -{ -public: - typedef Arr_ Arrangement; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef SnapStrategy< Traits > Superclass; - typedef typename Arrangement::Vertex_iterator Vertex_iterator; - typedef typename Kernel::Compute_squared_distance_2 - Compute_squared_distance_2; - typedef typename Kernel::FT FT; - typedef typename Traits::Point_2 Point_2; - typedef typename Kernel::Point_2 Kernel_point_2; - - SnapToArrangementVertexStrategy( ): - Superclass( NULL ), - arrangement( NULL ) - { } - - SnapToArrangementVertexStrategy( Arrangement* arr, QGraphicsScene* scene_ ): - Superclass( scene_ ), - arrangement( arr ) - { } - - Point_2 snapPoint( QGraphicsSceneMouseEvent* event ) - { - Kernel_point_2 clickedPoint = this->convert( event->scenePos( ) ); - return this->snapPoint( clickedPoint, Traits( ) ); - } - - template < class TTraits > - Point_2 snapPoint(const Kernel_point_2& clickedPoint, TTraits /* traits */) - { - Point_2 initialPoint( CGAL::to_double(clickedPoint.x()), - CGAL::to_double(clickedPoint.y()) ); - Point_2 closestPoint( CGAL::to_double(clickedPoint.x()), - CGAL::to_double(clickedPoint.y()) ); - bool first = true; - FT minDist( 0 ); - QRectF viewportRect = this->viewportRect( ); - if ( viewportRect == QRectF( ) ) - { - return initialPoint; - } - - FT maxDist( ( viewportRect.right( ) - viewportRect.left( ) ) / 4.0 ); - for ( Vertex_iterator vit = this->arrangement->vertices_begin( ); - vit != this->arrangement->vertices_end( ); ++vit ) - { - Point_2 point = vit->point( ); - Kernel_point_2 thisPoint( CGAL::to_double(point.x()), - CGAL::to_double(point.y()) ); - FT dist = this->compute_squared_distance_2( clickedPoint, thisPoint ); - if ( first || ( dist < minDist ) ) - { - first = false; - minDist = dist; - closestPoint = point; - } - } - if ( ! first && minDist < maxDist ) - { - return closestPoint; - } - else - { - return initialPoint; - } - } - - template < class CircularKernel > - Point_2 snapPoint(const Kernel_point_2& clickedPoint, - CGAL::Arr_circular_arc_traits_2 - /* traits */) - { - typedef Kernel_point_2 Non_arc_point_2; - typedef typename CircularKernel::Circular_arc_point_2 Arc_point_2; - - Non_arc_point_2 closestKernelPoint = clickedPoint; - Arc_point_2 closestPoint( closestKernelPoint ); - bool first = true; - FT minDist( 0 ); - QRectF viewportRect = this->viewportRect( ); - if ( viewportRect == QRectF( ) ) - { - return clickedPoint; - } - - FT maxDist( ( viewportRect.right( ) - viewportRect.left( ) ) / 4.0 ); - for ( Vertex_iterator vit = this->arrangement->vertices_begin( ); - vit != this->arrangement->vertices_end( ); ++vit ) - { - Arc_point_2 point = vit->point( ); - Non_arc_point_2 point2( CGAL::to_double(point.x( )), - CGAL::to_double(point.y()) ); - FT dist = this->compute_squared_distance_2( clickedPoint, point2 ); - if ( first || ( dist < minDist ) ) - { - first = false; - minDist = dist; - //closestPoint = point2; - closestPoint = point; - } - } - if ( ! first && minDist < maxDist ) - { - return closestPoint; - } - else - { - return clickedPoint; - } - } - - void setArrangement( Arrangement* arr ) - { - this->arrangement = arr; - } - -protected: - Arrangement* arrangement; - Compute_squared_distance_2 compute_squared_distance_2; - CGAL::Qt::Converter< Kernel > convert; -}; // class SnapToArrangementVertexStrategy - -/** - Converts between Kernel points and Arrangement points. - - The conversion is not necessarily exact. -*/ -template < class ArrTraits > -class Arr_construct_point_2 -{ - typedef typename ArrTraits::Point_2 Point_2; - typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType CoordinateType; - typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; - typedef typename Kernel::Point_2 Kernel_point_2; - -public: - Point_2 operator()( const Kernel_point_2& pt ) - { - return (*this)( pt.x(), pt.y() ); - } - - template < class T > - Point_2 operator()( const T& x, const T& y ) - { - return (*this)( x, y, ArrTraits( ) ); - } - -protected: - template < class T, class TTraits > - Point_2 operator()(const T& x, const T& y, TTraits /* traits */) - { - CoordinateType xx( x ); - CoordinateType yy( y ); - Point_2 res( xx, yy ); - return res; - } - - template < class T, class CircularKernel > - Point_2 operator()(const T& x, const T& y, - CGAL::Arr_circular_arc_traits_2 - /* traits */) - { - typedef typename CircularKernel::Root_for_circles_2_2 Root_for_circles_2_2; - CoordinateType xx( x ); - CoordinateType yy( y ); - Root_for_circles_2_2 p( xx, yy ); - Point_2 res( p ); - return res; - } -}; - -class Find_nearest_edge_base : public QGraphicsSceneMixin -{ -public: - /*! Destructor (virtual) */ - virtual ~Find_nearest_edge_base() {} -}; - -template < class Arr_, class ArrTraits = typename Arr_::Geometry_traits_2 > -class Find_nearest_edge : public Find_nearest_edge_base -{ -public: // typedefs - typedef Arr_ Arrangement; - //typedef typename Arrangement::Geometry_traits_2 ArrTraits; - typedef Compute_squared_distance_2< ArrTraits > Point_curve_distance; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef CGAL::Arr_walk_along_line_point_location< Arrangement > - Point_location_strategy; - typedef typename ArrTraitsAdaptor::Kernel Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Arrangement::Face_const_handle Face_const_handle; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Point_curve_distance::FT FT; - typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; - typedef typename Arrangement::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - -public: - /*! constructor */ - Find_nearest_edge( Arrangement* arr_ ) : - Find_nearest_edge_base( ), - arr( arr_ ), - pointLocationStrategy( Point_location_strategy( *arr_ ) ) - { } - - /*! Destructor (virtual) */ - virtual ~Find_nearest_edge() {} - -public: // member methods - Halfedge_const_handle operator()( const Point_2& queryPt ) - { - typename ArrTraits::Point_2 pt = this->toArrPoint( queryPt ); - CGAL::Object pointLocationResult = this->pointLocationStrategy.locate( pt ); - Face_const_handle face = this->getFace( pointLocationResult ); - bool first = 1; - X_monotone_curve_2 closestCurve; - Halfedge_const_handle closestEdge; - double minDist( 0 ); - - if ( ! face->is_unbounded( ) ) - { // it is an interior face so it has a ccb - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - } - while ( ++cc != face->outer_ccb( ) ); - } -#if 0 // we can't do this with bounded arrangements - else - { - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - if ( cc->is_fictitious( ) ) - { - continue; - } - - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - } - while ( ++cc != face->outer_ccb( ) ); - } -#endif - Hole_const_iterator hit; - Hole_const_iterator eit = face->holes_end( ); - // int counter = 0; - for ( hit = face->holes_begin( ); hit != eit; ++hit ) - { // check any holes inside this face - Ccb_halfedge_const_circulator cc = *hit; - do - { - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - cc++; - } - while ( cc != *hit ); - } - - return closestEdge; - } - - virtual void setScene( QGraphicsScene* scene_ ) - { - this->pointCurveDistance.setScene( scene_ ); - Find_nearest_edge_base::setScene( scene_ ); - } - -protected: // member methods - Face_const_handle getFace( const CGAL::Object& obj ) - { - Face_const_handle f; - if ( CGAL::assign( f, obj ) ) - return f; - - Halfedge_const_handle he; - if (CGAL::assign( he, obj )) - return (he->face( )); - - Vertex_const_handle v; - CGAL_assertion(CGAL::assign( v, obj )); - CGAL::assign( v, obj ); - if ( v->is_isolated( ) ) - return v->face( ); - Halfedge_around_vertex_const_circulator eit = v->incident_halfedges( ); - return (eit->face( )); - } - -protected: // member fields - Arrangement* arr; - Point_curve_distance pointCurveDistance; - Point_location_strategy pointLocationStrategy; - Arr_construct_point_2< ArrTraits > toArrPoint; - -}; // class Find_nearest_edge - -#if 0 -template < class Arr_, class Coefficient_ > -class Find_nearest_edge >: public Find_nearest_edge_base -{ -public: - Halfedge_const_handle operator()( const Point_2& queryPt ) { } -}; -#endif - -template < class Arr_, class Kernel_ > -class Find_nearest_edge< Arr_, CGAL::Arr_linear_traits_2< Kernel_ > > : - public Find_nearest_edge_base -{ -public: // typedefs - typedef Arr_ Arrangement; - typedef typename Arrangement::Geometry_traits_2 ArrTraits; - typedef Compute_squared_distance_2< ArrTraits > Point_curve_distance; - typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; - typedef CGAL::Arr_walk_along_line_point_location< Arrangement > - Point_location_strategy; - typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; - typedef typename Kernel::Point_2 Point_2; - typedef typename Arrangement::Face_const_handle Face_const_handle; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Point_curve_distance::FT FT; - typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; - typedef typename Arrangement::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - -public: // constructors - Find_nearest_edge( Arrangement* arr_ ) : - Find_nearest_edge_base( ), - arr( arr_ ), - pointLocationStrategy( Point_location_strategy( *arr_ ) ) - { } - -public: // member methods - Halfedge_const_handle operator()( const Point_2& queryPt ) - { - CGAL::Object pointLocationResult = - this->pointLocationStrategy.locate( queryPt ); - Face_const_handle face = this->getFace( pointLocationResult ); - bool first = 1; - X_monotone_curve_2 closestCurve; - Halfedge_const_handle closestEdge; - double minDist( 0 ); - - if ( ! face->is_unbounded( ) ) - { // it is an interior face so it has a ccb - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - } - while ( ++cc != face->outer_ccb( ) ); - } - else - { - Ccb_halfedge_const_circulator cc = face->outer_ccb( ); - do - { - if ( cc->is_fictitious( ) ) - { - continue; - } - - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - } - while ( ++cc != face->outer_ccb( ) ); - } - Hole_const_iterator hit; - Hole_const_iterator eit = face->holes_end( ); - for ( hit = face->holes_begin( ); hit != eit; ++hit ) - { // check any holes inside this face - Ccb_halfedge_const_circulator cc = *hit; - do - { - X_monotone_curve_2 curve = cc->curve( ); - double dist = this->pointCurveDistance( queryPt, curve ); - if ( first || dist < minDist ) - { - first = 0; - minDist = dist; - closestEdge = cc; - } - cc++; - } - while ( cc != *hit ); - } - - return closestEdge; - } - -protected: // member methods - Face_const_handle getFace( const CGAL::Object& obj ) - { - Face_const_handle f; - if ( CGAL::assign( f, obj ) ) - return f; - - Halfedge_const_handle he; - if (CGAL::assign( he, obj )) - return (he->face( )); - - Vertex_const_handle v; - CGAL_assertion(CGAL::assign( v, obj )); - CGAL::assign( v, obj ); - if ( v->is_isolated( ) ) - return v->face( ); - Halfedge_around_vertex_const_circulator eit = v->incident_halfedges( ); - return (eit->face( )); - } - -protected: // member fields - Arrangement* arr; - Point_curve_distance pointCurveDistance; - Point_location_strategy pointLocationStrategy; -}; // class Find_nearest_edge - -#endif // CGAL_ARRANGEMENTS_DEMO_UTILS_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp new file mode 100644 index 00000000000..9c1c8fbc83d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.cpp @@ -0,0 +1,337 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "ConstructBoundingBox.h" +#include "ForwardDeclarations.h" +#include "ArrangementTypes.h" + +#include +#include + +static const CGAL::Bbox_2 inf_bbox = { + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + std::numeric_limits::infinity(), + std::numeric_limits::infinity()}; + +static constexpr double inf_double = std::numeric_limits::infinity(); + +template +struct ConstructBoundingBox_impl +{ + using Traits = Traits_; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { +#ifdef CGAL_USE_CORE + using Zero_resultant_exception = CGAL::internal::Zero_resultant_exception< + typename demo_types::DemoTypes::Alg_seg_traits::Polynomial_2>; +#endif + + CGAL::Bbox_2 bbox; + try + { + bbox = curve.bbox(); + } + // algebraic traits sometimes crash when calling bbox + // example: xy=0 + catch (std::exception& ex) + { + std::cerr << ex.what() << '\n'; + std::cerr << __FILE__ << ':' << __LINE__ << '\n'; + bbox = inf_bbox; + } +#ifdef CGAL_USE_CORE + catch (Zero_resultant_exception&) + { + std::cerr << "Exception thrown of type \"Zero_resultant_exception\"\n"; + std::cerr << __FILE__ << ':' << __LINE__ << '\n'; + bbox = inf_bbox; + } +#endif + catch (...) + { + std::cerr << "Exception thrown of unknown type!\n"; + std::cerr << __FILE__ << ':' << __LINE__ << '\n'; + bbox = inf_bbox; + } + return bbox; + } + + CGAL::Bbox_2 + operator()(const Point_2& point) + { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } +}; + +// We currently avoid using bbox function in Arr_sgegment_2 because it creates +// its own kernel object +// TODO: remove this class and the polyline one once it's fixed +// and use bbox directly +template +struct ConstructBoundingBox_impl> +{ + using Traits = CGAL::Arr_segment_traits_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { + return this->operator()(curve.source(), curve.target()); + } + + CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) + { + CGAL::Bbox_2 bbox; + double x1 = CGAL::to_double(p1.x()); + double y1 = CGAL::to_double(p1.y()); + double x2 = CGAL::to_double(p2.x()); + double y2 = CGAL::to_double(p2.y()); + + double min_x, max_x, min_y, max_y; + if (x1 < x2) + { + min_x = x1; + max_x = x2; + } + else + { + min_x = x2; + max_x = x1; + } + if (y1 < y2) + { + min_y = y1; + max_y = y2; + } + else + { + min_y = y2; + max_y = y1; + } + return {min_x, min_y, max_x, max_y}; + } + + CGAL::Bbox_2 + operator()(const Point_2& point) + { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } +}; + +template +struct ConstructBoundingBox_impl> +{ + using Traits = CGAL::Arr_polyline_traits_2; + using SegmentTraits_2 = SegmentTraits_2_; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { + ConstructBoundingBox_impl construct_bounding_box; + + auto n = curve.number_of_subcurves(); + CGAL::Bbox_2 bbox; + for (std::size_t i = 0; i < n; ++i) + bbox += construct_bounding_box(curve[i]); + + return bbox; + } + + CGAL::Bbox_2 operator()(const Point_2& p1, const Point_2& p2) + { + CGAL::Bbox_2 bbox; + double x1 = CGAL::to_double(p1.x()); + double y1 = CGAL::to_double(p1.y()); + double x2 = CGAL::to_double(p2.x()); + double y2 = CGAL::to_double(p2.y()); + + double min_x, max_x, min_y, max_y; + if (x1 < x2) + { + min_x = x1; + max_x = x2; + } + else + { + min_x = x2; + max_x = x1; + } + if (y1 < y2) + { + min_y = y1; + max_y = y2; + } + else + { + min_y = y2; + max_y = y1; + } + return {min_x, min_y, max_x, max_y}; + } + + CGAL::Bbox_2 + operator()(const Point_2& point) + { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } +}; + +template +struct ConstructBoundingBox_impl> +{ + using Traits = CGAL::Arr_linear_traits_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { + if (curve.is_segment()) + { + return ConstructBoundingBox_impl>{}( + curve.source(), curve.target()); + } + else if (curve.is_line()) + { + return inf_bbox; + } + // ray + else + { + auto&& ray = curve.ray(); + auto&& src = ray.source(); + double src_x = CGAL::to_double(src.x()); + double src_y = CGAL::to_double(src.y()); + auto&& dir = ray.direction(); + bool dx = CGAL::is_positive(dir.dx()); + bool dy = CGAL::is_positive(dir.dy()); + + if (dx && dy) + return {src_x, src_y, inf_double, inf_double}; + else if (!dx && dy) + return {-inf_double, src_y, src_x, inf_double}; + else if (!dx && !dy) + return {-inf_double, -inf_double, src_x, src_y}; + else // if (dx && !dy) + return {src_x, -inf_double, inf_double, src_y}; + } + } + + CGAL::Bbox_2 operator()(const Point_2& point) + { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } +}; + + +template < + typename RatKernel_, typename AlgKernel_, typename NtTraits_, + typename BoundingTraits_> +struct ConstructBoundingBox_impl> +{ + using Traits = typename CGAL::Arr_Bezier_curve_traits_2< + RatKernel_, AlgKernel_, NtTraits_, BoundingTraits_>; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { + // TODO: find a way to find the bounding box of a bezier X_monotone_curve + return curve.supporting_curve().bbox(); + } + + CGAL::Bbox_2 + operator()(const Point_2& point) + { + std::pair p = point.approximate(); + return {p.first, p.second, p.first, p.second}; + } +}; + +template +struct ConstructBoundingBox_impl< + CGAL::Arr_rational_function_traits_2> +{ + using Traits = CGAL::Arr_rational_function_traits_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Curve_2 = typename Traits::Curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 + operator()(const X_monotone_curve_2& curve) + { + double min_x, max_x, min_y, max_y; + if (curve.left_parameter_space_in_x() == CGAL::ARR_INTERIOR) + min_x = CGAL::to_double(curve.left_x()); + else + min_x = -std::numeric_limits::infinity(); + + if (curve.right_parameter_space_in_x() == CGAL::ARR_INTERIOR) + max_x = CGAL::to_double(curve.right_x()); + else + max_x = std::numeric_limits::infinity(); + + // TODO: calculate min/max points of rational functions to better + // bound y coordinate + // the problem is where to store them? + // will also be useful for rendering + + min_y = -std::numeric_limits::infinity(); + max_y = std::numeric_limits::infinity(); + + return {min_x, min_y, max_x, max_y}; + } + + CGAL::Bbox_2 + operator()(const Point_2& point) + { + double x = CGAL::to_double(point.x()); + double y = CGAL::to_double(point.y()); + return {x, y, x, y}; + } +}; + +template +CGAL::Bbox_2 +ConstructBoundingBox::operator()(const X_monotone_curve_2& curve) +{ + return ConstructBoundingBox_impl{}(curve); +} +template +CGAL::Bbox_2 ConstructBoundingBox::operator()(const Point_2& point) +{ + return ConstructBoundingBox_impl{}(point); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(ConstructBoundingBox) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h new file mode 100644 index 00000000000..83b6e712f1b --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructBoundingBox.h @@ -0,0 +1,31 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_CONSTRUCT_BOUNDING_BOX +#define ARRANGEMENT_DEMO_CONSTRUCT_BOUNDING_BOX + +#include + +// bounding box utility for arrangements +// doesn't have to be exact, only good enough for rendering +template +class ConstructBoundingBox +{ +public: + using Traits = Traits_; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Point_2 = typename Traits::Point_2; + + CGAL::Bbox_2 operator()(const X_monotone_curve_2& curve); + CGAL::Bbox_2 operator()(const Point_2& point); +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.cpp new file mode 100644 index 00000000000..e5cb7176e93 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.cpp @@ -0,0 +1,106 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "ConstructSegment.h" +#include "ArrangementTypes.h" +#include "Utils.h" + +#include + +template +auto Construct_segment::operator()( + const Traits* traits, const Point_2& p1, const Point_2& p2) + -> X_monotone_curve_2 +{ + Arr_construct_point_2 toArrPoint{traits}; + + auto construct_x_monotone_curve_2 = + traits->construct_x_monotone_curve_2_object(); + return construct_x_monotone_curve_2(toArrPoint(p1), toArrPoint(p2)); +} + +template +auto Construct_segment>:: +operator()(const Traits* traits, const Point_2& p1, const Point_2& p2) + -> X_monotone_curve_2 +{ + Arr_construct_point_2 toArrPoint{traits}; + + auto construct_x_monotone_segment_2 = + traits->construct_x_monotone_segment_2_object(); + + std::vector curves; + construct_x_monotone_segment_2( + toArrPoint(p1), toArrPoint(p2), std::back_inserter(curves)); + return curves[0]; +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto Construct_segment>:: +operator()(const Traits* traits, const Point_2& p1, const Point_2& p2) + -> X_monotone_curve_2 +{ + Arr_construct_point_2 toArrPoint{traits}; + + typename Traits::Point_2 points[] = {toArrPoint(p1), toArrPoint(p2)}; + Curve_2 curve{points, points + 2}; + auto make_x_monotone = traits->make_x_monotone_2_object(); + std::vector curves; + make_x_monotone(curve, std::back_inserter(curves)); + X_monotone_curve_2 segment; + CGAL::assign(segment, curves[0]); + return segment; +} + +template +auto Construct_segment< + CGAL::Arr_rational_function_traits_2>:: +operator()(const Traits* traits, const Point_2& p1, const Point_2& p2) + -> X_monotone_curve_2 +{ + RationalTraits ratTraits; + + Rational dx = p2.x() - p1.x(); + Rational dy = p2.y() - p1.y(); + Polynomial_1 x = CGAL::shift(Polynomial_1(1), 1, 0); + Polynomial_1 poly_num; + Polynomial_1 poly_den; + + if (dx != 0) + { + Rational mRat = dy / dx; + Rational cRat = p1.y() - mRat * p1.x(); + // y = (a/b) x + (e/f) + auto a = ratTraits.numerator(mRat); + auto b = ratTraits.denominator(mRat); + auto e = ratTraits.numerator(cRat); + auto f = ratTraits.denominator(cRat); + + poly_num = f * a * x + b * e; + poly_den = Polynomial_1{b * f}; + } + else + { + throw std::runtime_error( + "Vertical split segments are not allowed with rational traits!\n"); + } + + auto construct_x_monotone_curve_2 = + traits->construct_x_monotone_curve_2_object(); + + return construct_x_monotone_curve_2( + poly_num, poly_den, Algebraic_real_1{p1.x()}, Algebraic_real_1{p2.x()}); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Construct_segment) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.h new file mode 100644 index 00000000000..6e80f44001a --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/ConstructSegment.h @@ -0,0 +1,79 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_CONSTRUCT_SEGMENT +#define ARRANGEMENT_DEMO_CONSTRUCT_SEGMENT + +#include "CurveInputMethods.h" +#include "ForwardDeclarations.h" + +// creates a line segment between two points of the type resulting from +// user input (CurveInputMethod::Point_2) +template +class Construct_segment +{ +public: + using Traits = Traits_; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + + X_monotone_curve_2 + operator()(const Traits* traits, const Point_2& p1, const Point_2& p2); +}; + +template +class Construct_segment> +{ +public: + using Traits = CGAL::Arr_algebraic_segment_traits_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + + X_monotone_curve_2 + operator()(const Traits* traits, const Point_2& p1, const Point_2& p2); +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class Construct_segment> +{ +public: + using Traits = CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits>; + using Curve_2 = typename Traits::Curve_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + + X_monotone_curve_2 + operator()(const Traits* traits, const Point_2& p1, const Point_2& p2); +}; + +template +class Construct_segment< + CGAL::Arr_rational_function_traits_2> +{ +public: + using Traits = CGAL::Arr_rational_function_traits_2; + using Rational = typename Traits::Rational; + using Integer = typename Traits::Integer; + using Polynomial_1 = typename Traits::Polynomial_1; + using Algebraic_real_1 = typename Traits::Algebraic_real_1; + using RationalTraits = CGAL::Rational_traits; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + using Point_2 = CGAL::Qt::CurveInputMethod::Point_2; + + X_monotone_curve_2 + operator()(const Traits* traits, const Point_2& p1, const Point_2& p2); +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.cpp new file mode 100644 index 00000000000..db807cd2f1d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "EnvelopeFunctions.h" +#include "ArrangementTypes.h" + +#include +#include +#include + +template +auto EnvelopeFunctions::getXMonotoneCurves(Arrangement* arr) + -> std::vector +{ + std::vector curves; + for (auto it = arr->edges_begin(); it != arr->edges_end(); ++it) + curves.push_back(it->curve()); + return curves; +} + +template +void EnvelopeFunctions::lowerEnvelope( + Arrangement* arr, Diagram_1& diagram) +{ + auto curves = getXMonotoneCurves(arr); + CGAL::lower_envelope_x_monotone_2( + curves.begin(), curves.end(), diagram, *(arr->traits())); +} + +template +void EnvelopeFunctions::upperEnvelope( + Arrangement* arr, Diagram_1& diagram) +{ + auto curves = getXMonotoneCurves(arr); + CGAL::upper_envelope_x_monotone_2( + curves.begin(), curves.end(), diagram, *(arr->traits())); +} + +ARRANGEMENT_DEMO_SPECIALIZE_ARR(EnvelopeFunctions) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.h new file mode 100644 index 00000000000..ce7689220b1 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/EnvelopeFunctions.h @@ -0,0 +1,34 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_ENVELOPE_FUNCTIONS +#define ARRANGEMENT_DEMO_ENVELOPE_FUNCTIONS + +#include +#include + +template +class EnvelopeFunctions +{ +public: + using Arrangement = Arr_; + using Traits = typename Arrangement::Geometry_traits_2; + using X_monotone_curve_2 = typename Arrangement::X_monotone_curve_2; + using Diagram_1 = CGAL::Envelope_diagram_1; + + void lowerEnvelope(Arrangement* arr, Diagram_1& diagram); + void upperEnvelope(Arrangement* arr, Diagram_1& diagram); + +private: + std::vector getXMonotoneCurves(Arrangement* arr); +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.cpp new file mode 100644 index 00000000000..f2d154c4eac --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "IntersectCurves.h" +#include "ArrangementTypes.h" + +template +Intersect_curves::Intersect_curves(const Traits* traits) : + intersect{traits->intersect_2_object()} +{ +} + +template +void Intersect_curves::operator()( + const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, + std::vector& output) +{ + this->intersect(cv1, cv2, std::back_inserter(output)); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Intersect_curves) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.h new file mode 100644 index 00000000000..193785b0250 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/IntersectCurves.h @@ -0,0 +1,37 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_INTERSECT_CURVES +#define ARRANGEMENT_DEMO_INTERSECT_CURVES + +#include + +// provides the same functionality as Traits::Intersect_2, but precompiled for +// all arrangements for better compilation speeds elsewhere +template +class Intersect_curves +{ +public: + using Traits = Traits_; + using Intersect_2 = typename Traits::Intersect_2; + using X_monotone_curve_2 = typename Traits::X_monotone_curve_2; + + Intersect_curves(const Traits*); + + void operator()( + const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, + std::vector& output); + +private: + Intersect_2 intersect; +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.cpp new file mode 100644 index 00000000000..39d27024cec --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include +#include +#include +#include +#include + +#include + +#include "ArrangementTypes.h" +#include "PointLocationFunctions.h" +#include "Utils/Utils.h" + +BOOST_MPL_HAS_XXX_TRAIT_DEF(Approximate_2) + +template ::value> +struct Supports_landmarks +{ + typedef CGAL::Boolean_tag Tag; +}; + +template +struct Supports_landmarks +{ + typedef CGAL::Tag_true Tag; +}; + +template +struct StrategyHelper +{ + using type = CGAL::Arr_walk_along_line_point_location; +}; + +template +struct StrategyHelper +{ + using type = CGAL::Arr_landmarks_point_location; +}; + +template +static auto toKernelPoint(const QPointF& pt) +{ + using Kernel = typename ArrTraitsAdaptor::Kernel; + return CGAL::Qt::Converter{}(pt); +} + +template +CGAL::Object PointLocationFunctions::locate( + const Arrangement* arr, const Kernel_point_2& pt) +{ + using SupportsLandmarks = typename Supports_landmarks::Tag; + using PointLocationStrategy = + typename StrategyHelper::type; + + Arr_construct_point_2 toArrPoint{arr->traits()}; + auto arr_point = toArrPoint(pt); + + PointLocationStrategy pointLocationStrategy{*arr}; + return pointLocationStrategy.locate(arr_point); +} + +template +auto PointLocationFunctions::getFace( + const Arrangement* arr, const Kernel_point_2& pt) -> Face_const_handle +{ + CGAL::Object obj = locate(arr, pt); + + Face_const_handle f; + if (CGAL::assign(f, obj)) return f; + + Halfedge_const_handle he; + if (CGAL::assign(he, obj)) return (he->face()); + + Vertex_const_handle v; + CGAL_assertion(CGAL::assign(v, obj)); + + CGAL::assign(v, obj); + if (v->is_isolated()) return v->face(); + Halfedge_around_vertex_const_circulator eit = v->incident_halfedges(); + return (eit->face()); +} + +template +CGAL::Object +PointLocationFunctions::locate(const Arrangement* arr, const QPointF& pt) +{ + return this->locate(arr, toKernelPoint(pt)); +} + +template +auto PointLocationFunctions::getFace( + const Arrangement* arr, const QPointF& pt) -> Face_const_handle +{ + return this->getFace(arr, toKernelPoint(pt)); +} + +template +CGAL::Object PointLocationFunctions::rayShootUp( + const Arrangement* arr, const QPointF& pt) +{ + using Walk_pl_strategy = + typename CGAL::Arr_walk_along_line_point_location; + + Arr_construct_point_2 toArrPoint{arr->traits()}; + Walk_pl_strategy pointLocationStrategy{*arr}; + return pointLocationStrategy.ray_shoot_up( + toArrPoint(toKernelPoint(pt))); +} + +template +CGAL::Object PointLocationFunctions::rayShootDown( + const Arrangement* arr, const QPointF& pt) +{ + using Walk_pl_strategy = + typename CGAL::Arr_walk_along_line_point_location; + + Arr_construct_point_2 toArrPoint{arr->traits()}; + Walk_pl_strategy pointLocationStrategy{*arr}; + return pointLocationStrategy.ray_shoot_down( + toArrPoint(toKernelPoint(pt))); +} + +ARRANGEMENT_DEMO_SPECIALIZE_ARR(PointLocationFunctions) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.h new file mode 100644 index 00000000000..63d7297ecf3 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/PointLocationFunctions.h @@ -0,0 +1,43 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_POINT_LOCATION_FUNCTIONS +#define ARRANGEMENT_DEMO_POINT_LOCATION_FUNCTIONS + +#include +#include "ArrTraitsAdaptor.h" + +class QPointF; + +template +class PointLocationFunctions +{ +public: + using Arrangement = Arr_; + using Traits = typename Arrangement::Geometry_traits_2; + using Halfedge_const_handle = typename Arrangement::Halfedge_const_handle; + using Face_const_handle = typename Arrangement::Face_const_handle; + using Vertex_const_handle = typename Arrangement::Vertex_const_handle; + using Halfedge_around_vertex_const_circulator = + typename Arrangement::Halfedge_around_vertex_const_circulator; + using Kernel = typename ArrTraitsAdaptor::Kernel; + using Kernel_point_2 = typename Kernel::Point_2; + + // the QPointF versions are for convenience + CGAL::Object locate(const Arrangement*, const Kernel_point_2&); + CGAL::Object locate(const Arrangement*, const QPointF&); + Face_const_handle getFace(const Arrangement*, const Kernel_point_2&); + Face_const_handle getFace(const Arrangement*, const QPointF&); + CGAL::Object rayShootUp(const Arrangement*, const QPointF&); + CGAL::Object rayShootDown(const Arrangement*, const QPointF&); +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.cpp new file mode 100644 index 00000000000..e62a7945fbd --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#include "SplitAndMerge.h" +#include "ArrangementTypes.h" + +template +void Split_edge::operator()( + Arrangement* arr, Halfedge_handle hei, const Point_2& pt) +{ + // check if split point lies on the edge of the curve + Equal_2 areEqual(arr->traits()->equal_2_object()); + if ( + (!hei->source()->is_at_open_boundary() && + areEqual(hei->source()->point(), pt)) || + (!hei->target()->is_at_open_boundary() && + areEqual(hei->target()->point(), pt))) + { return; } + + arr->split_edge(hei, pt); +} + +template +void Merge_edge::mergeEdge( + Arrangement* arr, Halfedge_handle h1, Halfedge_handle h2) +{ + arr->merge_edge(h1, h2); +} + +template +bool Merge_edge::areMergeable( + Arrangement* arr, Halfedge_handle h1, Halfedge_handle h2) +{ + return arr->are_mergeable(h1, h2); +} + +ARRANGEMENT_DEMO_SPECIALIZE_ARR(Split_edge) +ARRANGEMENT_DEMO_SPECIALIZE_ARR(Merge_edge) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.h new file mode 100644 index 00000000000..ea7a22f63ee --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/SplitAndMerge.h @@ -0,0 +1,45 @@ +// Copyright (c) 2020 GeometryFactory Sarl (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Ahmed Essam + +#ifndef ARRANGEMENT_DEMO_SPLIT_AND_MERGE +#define ARRANGEMENT_DEMO_SPLIT_AND_MERGE + +// provides the same functionality as Arrangement_with_history_2::split_edge, +// but precompiled for all arrangements for better compilation speeds elsewhere +template +class Split_edge +{ +public: + using Arrangement = Arr_; + using Traits = typename Arrangement::Geometry_traits_2; + using Halfedge_handle = typename Arrangement::Halfedge_handle; + using Point_2 = typename Traits::Point_2; + using Equal_2 = typename Traits::Equal_2; + + void operator()(Arrangement*, Halfedge_handle, const Point_2&); +}; + +// provides the same functionality as Arrangement_with_history_2::merge_edge, +// but precompiled for all arrangements for better compilation speeds elsewhere +template +class Merge_edge +{ +public: + using Arrangement = Arr_; + using Traits = typename Arrangement::Geometry_traits_2; + using Halfedge_handle = typename Arrangement::Halfedge_handle; + using Point_2 = typename Traits::Point_2; + + void mergeEdge(Arrangement*, Halfedge_handle, Halfedge_handle); + bool areMergeable(Arrangement*, Halfedge_handle, Halfedge_handle); +}; + +#endif diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp new file mode 100644 index 00000000000..3d93dd822db --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.cpp @@ -0,0 +1,906 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#include "ArrangementPainterOstream.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" + +#include "PointLocationFunctions.h" +#include "Utils.h" + +#include +#include + +#include +#include + +template +double +Compute_squared_distance_2>::operator()( + const Point_2& p, const X_monotone_curve_2& c) const +{ + Point_2 p1 = c.source(); + Point_2 p2 = c.target(); + Segment_2 seg(p1, p2); + + return CGAL::to_double(CGAL::squared_distance(p, seg)); +} + +template +double +Compute_squared_distance_2>::operator()( + const Point_2& p, const X_monotone_curve_2& c) const +{ + Segment_2 seg; + Ray_2 ray; + Line_2 line; + FT res; + if (c.is_segment()) + { + seg = c.segment(); + res = CGAL::squared_distance(p, seg); + } + else if (c.is_ray()) + { + ray = c.ray(); + res = CGAL::squared_distance(p, ray); + } + else // ( c.is_line( ) ) + { + line = c.line(); + res = CGAL::squared_distance(p, line); + } + return CGAL::to_double(res); +} + +template +double +Compute_squared_distance_2>::operator()( + const Point_2& p, const X_monotone_curve_2& c) const +{ + Seg_const_it seg_it_s = c.subcurves_begin(); + + bool first = true; + FT min_dist = 0; + + while (seg_it_s != c.subcurves_end()) + { + Segment_2 seg = *seg_it_s; + FT dist = CGAL::squared_distance(p, seg); + + if (first || dist < min_dist) + { + first = false; + min_dist = dist; + } + seg_it_s++; + } + + return CGAL::to_double(min_dist); +} + +template +double Compute_squared_distance_2< + CGAL::Arr_conic_traits_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& c) const +{ + // Get the co-ordinates of the curve's source and target. + // double sx = CGAL::to_double( c.source( ).x( ) ); + // double sy = CGAL::to_double( c.source( ).y( ) ); + // double tx = CGAL::to_double( c.target( ).x( ) ); + // double ty = CGAL::to_double( c.target( ).y( ) ); + + if (c.orientation() == CGAL::COLLINEAR) + { + Point_2 ps = c.source(); + Point_2 pt = c.target(); + Segment_2 seg(ps, pt); + + FT res = CGAL::squared_distance(p, seg); + return CGAL::to_double(res); + } + else + { + // If the curve is monotone, than its source and its target has the + // extreme x co-ordinates on this curve. + // bool is_source_left = (sx < tx); + // int x_min = is_source_left ? (*w).x_pixel(sx) : (*w).x_pixel(tx); + // int x_max = is_source_left ? (*w).x_pixel(tx) : (*w).x_pixel(sx); + // double prev_x = is_source_left ? sx : tx; + // double prev_y = is_source_left ? sy : ty; + // double curr_x, curr_y; + // int x; + // Arr_conic_point_2 px; + + bool first = true; + FT min_dist(100000000); + // AlgKernel ker; + + int n = 100; + if (this->scene != NULL && this->scene->views().size() != 0) + { // use the scene to approximate the resolution of the curve + QGraphicsView* view = this->scene->views().first(); + CGAL::Bbox_2 bb = c.bbox(); // assumes bounded curve + int xmin = view->mapFromScene(bb.xmin(), bb.ymin()).x(); + int xmax = view->mapFromScene(bb.xmax(), bb.ymin()).x(); + n = xmax - xmin; + if (n < 2) { n = 2; } + } + + std::vector> app_pts; + app_pts.reserve(n + 1); + c.polyline_approximation(n, std::back_inserter(app_pts)); + auto end_pts = app_pts.end(); + auto p_curr = app_pts.begin(); + auto p_next = p_curr + 1; + do + { + Point_2 p1(p_curr->first, p_curr->second); + Point_2 p2(p_next->first, p_next->second); + Segment_2 seg(p1, p2); + + FT dist = CGAL::squared_distance(p, seg); + if (first || dist < min_dist) + { + first = false; + min_dist = dist; + } + + p_curr++; + p_next++; + } while (p_next != end_pts); + + return CGAL::to_double(min_dist); + } +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +double Compute_squared_distance_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& curve) const +{ + // TODO: this should probably be cached! + CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; + painterOstream.setScene(this->getScene()); + + std::pair p_pair = { + CGAL::to_double(p.x()), CGAL::to_double(p.y())}; + + double minDist = (std::numeric_limits::max)(); + auto points = painterOstream.getPoints(curve); + for (auto& vit : points) + { + QPointF coord(vit.first, vit.second); + float curDist = (vit.first - p_pair.first) * (vit.first - p_pair.first) + + (vit.second - p_pair.second) * (vit.second - p_pair.second); + minDist = curDist < minDist ? curDist : minDist; + } + return minDist; +} + +template +double +Compute_squared_distance_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& curve) const +{ + // TODO: this should probably be cached! + CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; + painterOstream.setScene(this->getScene()); + + auto view = this->getView(); + QTransform worldTransform; + worldTransform.translate( + -view->horizontalScrollBar()->value(), -view->verticalScrollBar()->value()); + worldTransform = view->transform() * worldTransform; + + QTransform facadeToViewport = + painterOstream.getPointsListMapping(worldTransform); + + auto points = painterOstream.getPointsList(curve); + + QPoint p_viewport = + view->mapFromScene(QPointF{p.x().doubleValue(), p.y().doubleValue()}); + + double minDist = (std::numeric_limits::max)(); + for (auto& vec : points) + { + for (auto vit = vec.begin(); vit != vec.end(); ++vit) + { + QPoint coord(vit->first, vit->second); + float curDist = QLineF{facadeToViewport.map(coord), p_viewport}.length(); + minDist = curDist < minDist ? curDist : minDist; + } + } + + return minDist; +} + +template +double Compute_squared_distance_2< + CGAL::Arr_rational_function_traits_2>:: +operator()(const Point_2& p, const X_monotone_curve_2& curve) const +{ + // TODO: this should probably be cached! + CGAL::Qt::ArrangementPainterOstream painterOstream{nullptr}; + painterOstream.setScene(this->getScene()); + + std::pair p_pair = { + CGAL::to_double(p.x()), CGAL::to_double(p.y())}; + + double minDist = (std::numeric_limits::max)(); + auto points_list = painterOstream.getPointsList(curve); + for (auto& points : points_list) + { + for (auto& vit : points) + { + QPointF coord(vit.first, vit.second); + float curDist = + (vit.first - p_pair.first) * (vit.first - p_pair.first) + + (vit.second - p_pair.second) * (vit.second - p_pair.second); + minDist = curDist < minDist ? curDist : minDist; + } + } + return minDist; +} + +template +auto Arr_construct_point_2::operator()(const Kernel_point_2& pt) + -> Point_2 +{ + return (*this)(FT{pt.x()}, FT{pt.y()}, traits); +} + +template +auto Arr_construct_point_2::operator()(const FT& x, const FT& y) + -> Point_2 +{ + return (*this)(x, y, traits); +} + +template +template +auto Arr_construct_point_2::operator()( + const FT& x, const FT& y, const TTraits*) -> Point_2 +{ + CoordinateType xx(x); + CoordinateType yy(y); + Point_2 res(xx, yy); + return res; +} + +template +template +auto Arr_construct_point_2::operator()( + const FT& x, const FT& y, + const CGAL::Arr_rational_function_traits_2*) + -> Point_2 +{ + using Rational = typename ArrTraits::Rational; + using Rational_function = typename ArrTraits::Rational_function; + using Polynomial_1 = typename ArrTraits::Polynomial_1; + using RationalTraits = CGAL::Rational_traits; + + static AlgebraicKernel_d_1 algebraic_kernel; + + Rational y_rat{y}; + RationalTraits ratTraits; + + CoordinateType xx(x); + Polynomial_1 y_num{ratTraits.numerator(y_rat)}; + Polynomial_1 y_den{ratTraits.denominator(y_rat)}; + Rational_function yy{y_num, y_den, &algebraic_kernel}; + Point_2 res(yy, xx); + return res; +} + +template +auto Find_nearest_edge::operator()(const Point_2& queryPt) + -> Halfedge_const_handle +{ + Face_const_handle face = + PointLocationFunctions{}.getFace(arr, queryPt); + + bool first = 1; + X_monotone_curve_2 closestCurve; + Halfedge_const_handle closestEdge; + double minDist(0); + + if (!face->is_unbounded()) + { // it is an interior face so it has a ccb + Ccb_halfedge_const_circulator cc = face->outer_ccb(); + do + { + X_monotone_curve_2 curve = cc->curve(); + double dist = this->pointCurveDistance(queryPt, curve); + if (first || dist < minDist) + { + first = 0; + minDist = dist; + closestEdge = cc; + } + } while (++cc != face->outer_ccb()); + } + else if (face->has_outer_ccb()) + { + Ccb_halfedge_const_circulator cc = face->outer_ccb(); + do + { + if (cc->is_fictitious()) { continue; } + + X_monotone_curve_2 curve = cc->curve(); + double dist = this->pointCurveDistance(queryPt, curve); + if (first || dist < minDist) + { + first = 0; + minDist = dist; + closestEdge = cc; + } + } while (++cc != face->outer_ccb()); + } + Hole_const_iterator hit; + Hole_const_iterator eit = face->holes_end(); + // int counter = 0; + for (hit = face->holes_begin(); hit != eit; ++hit) + { // check any holes inside this face + Ccb_halfedge_const_circulator cc = *hit; + do + { + X_monotone_curve_2 curve = cc->curve(); + double dist = this->pointCurveDistance(queryPt, curve); + if (first || dist < minDist) + { + first = 0; + minDist = dist; + closestEdge = cc; + } + cc++; + } while (cc != *hit); + } + + return closestEdge; +} + +template +auto Find_nearest_edge::getFace(const CGAL::Object& obj) + -> Face_const_handle +{ + Face_const_handle f; + if (CGAL::assign(f, obj)) return f; + + Halfedge_const_handle he; + if (CGAL::assign(he, obj)) return (he->face()); + + Vertex_const_handle v; + CGAL_assertion(CGAL::assign(v, obj)); + CGAL::assign(v, obj); + if (v->is_isolated()) return v->face(); + auto eit = v->incident_halfedges(); + return (eit->face()); +} + +template +Construct_x_monotone_subcurve_2::Construct_x_monotone_subcurve_2( + const ArrTraits* traits_) : + traits(traits_), + split_2(this->traits->split_2_object()), + compare_x_2(this->traits->compare_x_2_object()), + compute_y_at_x(this->traits), + construct_min_vertex_2(this->traits->construct_min_vertex_2_object()), + construct_max_vertex_2(this->traits->construct_max_vertex_2_object()), + parameter_space_in_x_2(this->traits) +{ +} + +template +auto Construct_x_monotone_subcurve_2::operator()( + const X_monotone_curve_2& curve, const boost::optional& pLeft, + const boost::optional& pRight) -> X_monotone_curve_2 +{ + Point_2 pMin, pMax; + bool unbounded_min = false; + bool unbounded_max = false; + + if (this->parameter_space_in_x_2(curve, CGAL::ARR_MIN_END) != CGAL::INTERIOR) + unbounded_min = true; + else + pMin = this->construct_min_vertex_2(curve); + + if (this->parameter_space_in_x_2(curve, CGAL::ARR_MAX_END) != CGAL::INTERIOR) + unbounded_max = true; + else + pMax = this->construct_max_vertex_2(curve); + + X_monotone_curve_2 subcurve; + X_monotone_curve_2 unusedTrimmings; + X_monotone_curve_2 finalSubcurve; + if ( + pLeft && (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) + { + auto y1 = this->compute_y_at_x(curve, pLeft->x()); + + Point_2 splitPoint = {pLeft->x(), y1}; + this->split_2(curve, splitPoint, unusedTrimmings, subcurve); + } + else + { + subcurve = curve; + } + + if ( + pRight && + (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) + { + auto y2 = this->compute_y_at_x(subcurve, pRight->x()); + Point_2 splitPoint = {pRight->x(), y2}; + this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); + } + else + { + finalSubcurve = subcurve; + } + + return finalSubcurve; +} + +template +auto Construct_x_monotone_subcurve_2< + CGAL::Arr_conic_traits_2>:: +operator()( + const X_monotone_curve_2& curve, const boost::optional& pLeft, + const boost::optional& pRight) -> X_monotone_curve_2 +{ + // TODO: handle when pLeft or pRight is null + + // find the points on the curve + Point_2 left = curve.point_at_x(*pLeft); + Point_2 right = curve.point_at_x(*pRight); + + // make sure the points are oriented in the direction that the curve is + // going + AlgKernel ker; + if (!(((curve.is_directed_right()) && + ker.compare_xy_2_object()(left, right) == CGAL::SMALLER) || + ((!curve.is_directed_right()) && + ker.compare_xy_2_object()(left, right) == CGAL::LARGER))) + { std::swap(left, right); } + + X_monotone_curve_2 res = curve.trim(left, right); + return res; +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +Construct_x_monotone_subcurve_2>::Construct_x_monotone_subcurve_2(const ArrTraits* traits_) : + traits(traits_), + split_2(this->traits->split_2_object()), + compare_x_2(this->traits->compare_x_2_object()), + compute_y_at_x(this->traits), + construct_min_vertex_2(this->traits->construct_min_vertex_2_object()), + construct_max_vertex_2(this->traits->construct_max_vertex_2_object()) +{ +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto Construct_x_monotone_subcurve_2>:: +operator()( + const X_monotone_curve_2& curve, const boost::optional& pLeft, + const boost::optional& pRight) -> X_monotone_curve_2 +{ + auto pMin = this->construct_min_vertex_2(curve); + auto pMax = this->construct_max_vertex_2(curve); + + X_monotone_curve_2 subcurve; + X_monotone_curve_2 unusedTrimmings; + X_monotone_curve_2 finalSubcurve; + + // FIXME (maybe no way to fix it?): This is not optimal + // the envelope package returns x-monotone curves, and range [xbegin, xend] + // the range is algebraic, but we can't find "t" of the bezier curve + // at algebraic "x", so we need to make it rational + auto local_get_t = [&](auto&& point) { + if (point.is_rational()) + return this->compute_y_at_x.get_t( + curve, ((typename Point_2::Rat_point_2)point).x()); + else + return this->compute_y_at_x.get_t(curve, point.approximate().first); + }; + + if (pLeft && this->compare_x_2(*pLeft, pMin) == CGAL::LARGER) + { + auto t = local_get_t(*pLeft); + Point_2 splitPoint(curve.supporting_curve(), t); + this->split_2(curve, splitPoint, unusedTrimmings, subcurve); + } + else + { + subcurve = curve; + } + if (pRight && this->compare_x_2(*pRight, pMax) == CGAL::SMALLER) + { + auto t = local_get_t(*pRight); + Point_2 splitPoint(curve.supporting_curve(), t); + this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); + } + else + { + finalSubcurve = subcurve; + } + + return finalSubcurve; +} + +template +Construct_x_monotone_subcurve_2>::Construct_x_monotone_subcurve_2(const Traits* + traits_) : + traits(traits_), + split_2(this->traits->split_2_object()), + compare_x_2(this->traits->compare_x_2_object()), + compute_y_at_x(this->traits), + construct_min_vertex_2(this->traits->construct_min_vertex_2_object()), + construct_max_vertex_2(this->traits->construct_max_vertex_2_object()) +{ +} + +template +auto Construct_x_monotone_subcurve_2< + CGAL::Arr_rational_function_traits_2>:: +operator()( + const X_monotone_curve_2& curve, const boost::optional& pLeft, + const boost::optional& pRight) -> X_monotone_curve_2 +{ + Point_2 pMin, pMax; + bool unbounded_min = false; + bool unbounded_max = false; + try { pMin = this->construct_min_vertex_2(curve); } + catch (...) { unbounded_min = true; } + try { pMax = this->construct_max_vertex_2(curve); } + catch (...) { unbounded_max = true; } + + X_monotone_curve_2 subcurve; + X_monotone_curve_2 unusedTrimmings; + X_monotone_curve_2 finalSubcurve; + if ( + pLeft && (unbounded_min || this->compare_x_2(*pLeft, pMin) == CGAL::LARGER)) + { + Point_2 splitPoint{curve._f, pLeft->x()}; + this->split_2(curve, splitPoint, unusedTrimmings, subcurve); + } + else + { + subcurve = curve; + } + + if ( + pRight && + (unbounded_max || this->compare_x_2(*pRight, pMax) == CGAL::SMALLER)) + { + auto y2 = this->compute_y_at_x(subcurve, pRight->x()); + Point_2 splitPoint{curve._f, pRight->x()}; + this->split_2(subcurve, splitPoint, finalSubcurve, unusedTrimmings); + } + else + { + finalSubcurve = subcurve; + } + + return finalSubcurve; +} + +template +Arr_compute_y_at_x_2::Arr_compute_y_at_x_2(const Traits* traits_) : + traits(traits_), + intersectCurves(this->traits->intersect_2_object()) +{ +} + +template +auto Arr_compute_y_at_x_2::operator()( + const X_monotone_curve_2& curve, const CoordinateType& x) -> CoordinateType +{ + typename Traits::Left_side_category category; + return this->operator()(curve, x, this->traits, category); +} + +template +double Arr_compute_y_at_x_2::approx( + const X_monotone_curve_2& curve, const CoordinateType& x) +{ + return CGAL::to_double((*this)(curve, x)); +} + +template +template +auto Arr_compute_y_at_x_2::operator()( + const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_oblivious_side_tag) -> CoordinateType +{ + typedef + typename TTraits::Construct_x_monotone_curve_2 Construct_x_monotone_curve_2; + Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = + traits_->construct_x_monotone_curve_2_object(); + CoordinateType res(0); + CGAL::Bbox_2 clipRect = curve.bbox(); + Point_2 p1c1(x, CoordinateType(clipRect.ymin() - 1)); // clicked point + // upper bounding box + Point_2 p2c1(x, CoordinateType(clipRect.ymax() + 1)); + + const X_monotone_curve_2 verticalLine = + construct_x_monotone_curve_2(p1c1, p2c1); + CGAL::Object o; + CGAL::Oneset_iterator oi(o); + + this->intersectCurves(curve, verticalLine, oi); + + IntersectionResult pair; + if (CGAL::assign(pair, o)) + { + Point_2 pt = pair.first; + res = pt.y(); + } + return res; +} + +template +template +auto Arr_compute_y_at_x_2::operator()( + const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_open_side_tag) -> CoordinateType +{ + typename TTraits::Construct_x_monotone_curve_2 construct_x_monotone_curve_2 = + traits_->construct_x_monotone_curve_2_object(); + CoordinateType res(0); + // QRectF clipRect = this->viewportRect( ); + Line_2 line = curve.supporting_line(); + // FIXME: get a better bounding box for an unbounded segment + Point_2 p1c1(x, CoordinateType(-10000000)); // clicked point + Point_2 p2c1(x, CoordinateType(10000000)); // upper bounding box + + const X_monotone_curve_2 verticalLine = + construct_x_monotone_curve_2(p1c1, p2c1); + CGAL::Object o; + CGAL::Oneset_iterator oi(o); + + this->intersectCurves(curve, verticalLine, oi); + + IntersectionResult pair; + if (CGAL::assign(pair, o)) + { + Point_2 pt = pair.first; + res = pt.y(); + } + return res; +} + +template +auto Arr_compute_y_at_x_2>:: +operator()(const X_monotone_curve_2& curve, const CoordinateType& x) + -> CoordinateType +{ + CGAL::Object o; + CGAL::Oneset_iterator oi(o); + Intersect_2 intersect = traits->intersect_2_object(); + X_monotone_curve_2 c2 = this->makeVerticalLine(x); + intersect(curve, c2, oi); + std::pair res; + if (CGAL::assign(res, o)) // TODO: handle failure case + { + const Point_2& p = res.first; + CoordinateType coord = p.y(); + return coord; + } + else + { + std::cout << "Warning: vertical projection failed" << std::endl; + return CoordinateType(0); + } +} + +template +double +Arr_compute_y_at_x_2>:: + approx(const X_monotone_curve_2& curve, const CoordinateType& x) +{ + return CGAL::to_double(this->operator()(curve, x)); +} + +template +auto Arr_compute_y_at_x_2>:: + makeVerticalLine(const CoordinateType& x) -> X_monotone_curve_2 +{ + typename Traits::Construct_point_2 constructPoint = + traits->construct_point_2_object(); + typename Traits::Construct_x_monotone_segment_2 constructSegment = + traits->construct_x_monotone_segment_2_object(); + + std::vector curves; + Point_2 p1 = + constructPoint(x, CoordinateType(-(std::numeric_limits::max)())); + Point_2 p2 = + constructPoint(x, CoordinateType((std::numeric_limits::max)())); + constructSegment(p1, p2, std::back_inserter(curves)); + return curves[0]; // by construction, there is one curve in curves +} + +template +static inline auto get_t_range(const Bezier_x_monotone_2& curve) +{ + auto&& supp_curve = curve.supporting_curve(); + auto ps_org = curve.source().get_originator(supp_curve, curve.xid()); + CGAL_assertion(ps_org != curve.source().originators_end()); + + auto pt_org = curve.target().get_originator(supp_curve, curve.xid()); + CGAL_assertion(pt_org != curve.target().originators_end()); + + return std::make_pair( + (ps_org->point_bound().t_min + ps_org->point_bound().t_max) / 2, + (pt_org->point_bound().t_min + pt_org->point_bound().t_max) / 2); +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto Arr_compute_y_at_x_2>:: +operator()(const X_monotone_curve_2& curve, const Rational& x) -> Algebraic +{ + auto&& supp_curve = curve.supporting_curve(); + auto t = this->get_t(curve, x); + NtTraits nt_traits; + return nt_traits.evaluate_at(supp_curve.y_polynomial(), t) / + nt_traits.convert(supp_curve.y_norm()); +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +auto Arr_compute_y_at_x_2>:: + get_t(const X_monotone_curve_2& curve, const Rational& x) -> Algebraic +{ + std::vector t_vals; + curve.supporting_curve().get_t_at_x(x, std::back_inserter(t_vals)); + auto t_range = get_t_range(curve); + + const Algebraic& t_src{t_range.first}; + const Algebraic& t_trg{t_range.second}; + + for (auto t_iter = t_vals.begin(); t_iter != t_vals.end(); ++t_iter) + { + auto res1 = CGAL::compare(*t_iter, t_src); + if (res1 == CGAL::EQUAL) return (curve.source().y()); + auto res2 = CGAL::compare(*t_iter, t_trg); + if (res2 == CGAL::EQUAL) return (curve.target().y()); + if (res1 != res2) return *t_iter; + } + + CGAL_error(); + return 0; +} + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +double Arr_compute_y_at_x_2>::approx(const X_monotone_curve_2& curve, const Rational& x) +{ + return CGAL::to_double((*this)(curve, x)); +} + +template +auto Arr_compute_y_at_x_2< + CGAL::Arr_rational_function_traits_2>:: +operator()(const X_monotone_curve_2& curve, const Algebraic_real_1& x) + -> Algebraic_real_1 +{ + return Point_2{curve._f, x}.y(); +} + +template +auto Arr_compute_y_at_x_2< + CGAL::Arr_rational_function_traits_2>:: +operator()(const X_monotone_curve_2& curve, const Rational& x) -> Rational +{ + return curve._f.numer().evaluate(x) / curve._f.denom().evaluate(x); +} + +template +auto Arr_compute_y_at_x_2< + CGAL::Arr_rational_function_traits_2>:: +approx(const X_monotone_curve_2& curve, const Rational& x) -> double +{ + return CGAL::to_double((*this)(curve, x)); +} + +CGAL::Object createArrangement(demo_types::TraitsType tt) +{ + CGAL::Object res; + demo_types::visitArrangementType(tt, [&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + res = CGAL::make_object(new Arrangement()); + }); + return res; +} + +// Insert_curve +template +void Insert_curve::operator()(Arrangement* arr, const Curve_2& curve) +{ + CGAL::insert(*arr, curve); +} + +// free functions +void deleteArrangement(demo_types::TraitsType tt, const CGAL::Object& arr_obj) +{ + demo_types::visitArrangementType(tt, [&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + delete arr; + }); +} + +CGAL::Object makeOverlayArrangement(const std::vector& arrs) +{ + CGAL::Object arr_obj; + if (arrs.size() == 2) + { + demo_types::forEachArrangementType([&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + + Arrangement* arr1; + Arrangement* arr2; + if (CGAL::assign(arr1, arrs[0]) && CGAL::assign(arr2, arrs[1])) + { + auto overlay_arr = new Arrangement(); + CGAL::Arr_default_overlay_traits overlay_traits; + + CGAL::overlay(*arr1, *arr2, *overlay_arr, overlay_traits); + arr_obj = CGAL::make_object(overlay_arr); + } + }); + } + return arr_obj; +} + +void insertCurve( + demo_types::TraitsType tt, const CGAL::Object& arr_obj, + const CGAL::Object& curve_obj) +{ + demo_types::visitArrangementType(tt, [&](auto type_holder) { + using Arrangement = typename decltype(type_holder)::type; + using Curve_2 = typename Arrangement::Curve_2; + + Curve_2 curve; + Arrangement* arr; + if (!CGAL::assign(arr, arr_obj)) CGAL_error(); + if (!CGAL::assign(curve, curve_obj)) CGAL_error(); + + Insert_curve{}(arr, curve); + }); +} + +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Compute_squared_distance_2) +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Arr_construct_point_2) +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Construct_x_monotone_subcurve_2) +ARRANGEMENT_DEMO_SPECIALIZE_TRAITS(Arr_compute_y_at_x_2) +ARRANGEMENT_DEMO_SPECIALIZE_ARR(Find_nearest_edge) +ARRANGEMENT_DEMO_SPECIALIZE_ARR(Insert_curve) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h new file mode 100644 index 00000000000..0713d63f1c0 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/Utils/Utils.h @@ -0,0 +1,609 @@ +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Alex Tsui +// Ahmed Essam + +#ifndef CGAL_ARRANGEMENTS_DEMO_UTILS_H +#define CGAL_ARRANGEMENTS_DEMO_UTILS_H + +#include "ForwardDeclarations.h" +#include "GraphicsSceneMixin.h" +#include "ArrTraitsAdaptor.h" + +#include +#include +#include + +class QGraphicsScene; + +template +class Arr_compute_y_at_x_2 : public GraphicsSceneMixin +{ +public: + typedef ArrTraits Traits; + typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; + typedef typename ArrTraitsAdaptor< Traits >::CoordinateType CoordinateType; + // typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Line_2 Line_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::Intersect_2 Intersect_2; + typedef std::pair< typename Traits::Point_2, Multiplicity > + IntersectionResult; + + /*! Constructor */ + Arr_compute_y_at_x_2( const Traits* ); + + CoordinateType + operator()(const X_monotone_curve_2& curve, const CoordinateType& x); + + double approx(const X_monotone_curve_2& curve, const CoordinateType& x); + +protected: + template + CoordinateType operator()( + const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_oblivious_side_tag); + + template + CoordinateType operator()( + const X_monotone_curve_2& curve, const CoordinateType& x, + const TTraits* traits_, CGAL::Arr_open_side_tag); + +protected: + const Traits* traits; + Intersect_2 intersectCurves; +}; + +template +class Arr_compute_y_at_x_2< CGAL::Arr_algebraic_segment_traits_2< + Coefficient_ > > : public GraphicsSceneMixin +{ +public: + typedef Coefficient_ Coefficient; + typedef CGAL::Arr_algebraic_segment_traits_2< Coefficient > Traits; + typedef typename Traits::Algebraic_real_1 CoordinateType; + typedef typename Traits::Point_2 Point_2; + typedef typename Traits::Intersect_2 Intersect_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + Arr_compute_y_at_x_2(const Traits* traits_) : traits(traits_) { } + + CoordinateType + operator()(const X_monotone_curve_2& curve, const CoordinateType& x); + + double approx(const X_monotone_curve_2& curve, const CoordinateType& x); + +protected: + X_monotone_curve_2 makeVerticalLine(const CoordinateType& x); + const Traits* traits; +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class Arr_compute_y_at_x_2> : public GraphicsSceneMixin +{ +public: + typedef CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits> Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Rational Rational; + typedef typename Traits::Algebraic Algebraic; + typedef typename Traits::Point_2 Point_2; + + Arr_compute_y_at_x_2(const Traits*) { } + + Algebraic operator()(const X_monotone_curve_2& curve, const Rational& x); + double approx(const X_monotone_curve_2& curve, const Rational& x); + Algebraic get_t(const X_monotone_curve_2& curve, const Rational& x); +}; + +template +class Arr_compute_y_at_x_2< + CGAL::Arr_rational_function_traits_2> : + public GraphicsSceneMixin +{ +public: + typedef CGAL::Arr_rational_function_traits_2 Traits; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Algebraic_real_1 Algebraic_real_1; + typedef typename Traits::Point_2 Point_2; + typedef typename Traits::Rational Rational; + + Arr_compute_y_at_x_2(const Traits*) { } + + Algebraic_real_1 + operator()(const X_monotone_curve_2& curve, const Algebraic_real_1& x); + Rational + operator()(const X_monotone_curve_2& curve, const Rational& x); + double approx(const X_monotone_curve_2& curve, const Rational& x); +}; + +template +class Compute_squared_distance_2_base : public GraphicsSceneMixin +{ +}; + +template +class Compute_squared_distance_2 : + public Compute_squared_distance_2_base< ArrTraits > +{ }; + +template +class Compute_squared_distance_2< CGAL::Arr_segment_traits_2< Kernel_ > > : + public Compute_squared_distance_2_base > +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_segment_traits_2< Kernel > Traits; + typedef Compute_squared_distance_2_base< Traits > Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; +}; + +template +class Compute_squared_distance_2< CGAL::Arr_linear_traits_2< Kernel_ > > : + public Compute_squared_distance_2_base > +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_linear_traits_2< Kernel > Traits; + typedef Compute_squared_distance_2_base< Traits > Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Kernel::Ray_2 Ray_2; + typedef typename Kernel::Line_2 Line_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + + double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; +}; + +template +class Compute_squared_distance_2< CGAL::Arr_polyline_traits_2< Kernel_ > > : + public Compute_squared_distance_2_base > +{ +public: + typedef Kernel_ Kernel; + typedef CGAL::Arr_polyline_traits_2< Kernel > Traits; + typedef Compute_squared_distance_2_base< Traits > Superclass; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Traits::Curve_2 Curve_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Curve_2::Subcurve_const_iterator Seg_const_it; + + double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; +}; + +template +class Compute_squared_distance_2< CGAL::Arr_conic_traits_2< RatKernel, + AlgKernel, + NtTraits > > : + public Compute_squared_distance_2_base< CGAL::Arr_conic_traits_2< RatKernel, + AlgKernel, + NtTraits > > +{ +public: + typedef AlgKernel Kernel; + typedef CGAL::Arr_conic_traits_2< RatKernel, AlgKernel, NtTraits > Traits; + typedef Compute_squared_distance_2_base< Traits > Superclass; + // _Conic_point_2< AlgKernel > : public AlgKernel::Point_2 + typedef typename Traits::Point_2 Conic_point_2; + typedef typename Kernel::FT FT; + typedef typename Kernel::Point_2 Point_2; + typedef typename Kernel::Segment_2 Segment_2; + typedef typename Traits::Curve_2 Curve_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + +public: // methods + double operator() ( const Point_2& p, const X_monotone_curve_2& c ) const; +}; + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class Compute_squared_distance_2> : + public Compute_squared_distance_2_base> +{ +public: + typedef CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits> + Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + +public: // methods + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; +}; + +template +class Compute_squared_distance_2< + CGAL::Arr_rational_function_traits_2> : + public Compute_squared_distance_2_base< + CGAL::Arr_rational_function_traits_2> +{ +public: + typedef CGAL::Arr_rational_function_traits_2 Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + +public: + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; +}; + +template +class Compute_squared_distance_2< CGAL::Arr_algebraic_segment_traits_2< + Coefficient_ > > : + public Compute_squared_distance_2_base< CGAL::Arr_algebraic_segment_traits_2< + Coefficient_ > > +{ +public: + typedef Coefficient_ Coefficient; + typedef CGAL::Arr_algebraic_segment_traits_2 + Traits; + typedef typename Traits::Bound FT; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point_2; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::CKvA_2 CKvA_2; + typedef std::pair< double, double > Coord_2; + typedef std::vector< Coord_2 > Coord_vec_2; + typedef typename X_monotone_curve_2::Curve_analysis_2 Curve; + typedef typename Curve::Polynomial_traits_2 Polynomial_traits_2; + typedef typename Curve::Polynomial_2 Polynomial_2; + typedef typename Polynomial_traits_2::Multivariate_content + Multivariate_content; + typedef typename Polynomial_traits_2::Substitute Substitute; + typedef typename Polynomial_traits_2:: + Construct_innermost_coefficient_const_iterator_range + ConstructInnerCoeffIter; + +public: + double operator()(const Point_2& p, const X_monotone_curve_2& c) const; +}; + +// chcek if arrangement is a model of the concept ArrangementOpenBoundaryTraits_2 +template +struct IsOpenBoundaryArrangement : + public CGAL::Boolean_tag< + std::is_convertible< + typename ArrTraits::Left_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Bottom_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Top_side_category, + CGAL::Arr_open_side_tag>::value && + std::is_convertible< + typename ArrTraits::Right_side_category, + CGAL::Arr_open_side_tag>::value> +{ +}; + +template +class Param_space_in_x_2 +{ +public: + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + + Param_space_in_x_2(const ArrTraits*) {} + CGAL::Arr_parameter_space + operator()(const X_monotone_curve_2&, CGAL::Arr_curve_end) + { + return CGAL::INTERIOR; + } +}; + +template +class Param_space_in_x_2< + ArrTraits, std::enable_if_t::value>> +{ +public: + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraits::Parameter_space_in_x_2 Parameter_space_in_x_2; + + Param_space_in_x_2(const ArrTraits* traits) : + parameter_space_in_x_2(traits->parameter_space_in_x_2_object()) + { + } + + CGAL::Arr_parameter_space + operator()(const X_monotone_curve_2& curve, CGAL::Arr_curve_end curve_end) + { + return this->parameter_space_in_x_2(curve, curve_end); + } + +private: + Parameter_space_in_x_2 parameter_space_in_x_2; +}; + +template +class Construct_x_monotone_subcurve_2 +{ +public: + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraits::Split_2 Split_2; + typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; + typedef typename ArrTraits::Compare_x_2 Compare_x_2; + typedef Param_space_in_x_2 Parameter_space_in_x_2; + typedef typename ArrTraits::Point_2 Point_2; + + Construct_x_monotone_subcurve_2( const ArrTraits* traits_ ); + + /* + Return the subcurve of curve bracketed by pLeft and pRight. + + We assume pLeft and pRight don't lie on the curve and always do a vertical + projection. + */ + X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight ); + +protected: + const ArrTraits* traits; + Split_2 split_2; + Compare_x_2 compare_x_2; + Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; + Construct_min_vertex_2 construct_min_vertex_2; + Construct_max_vertex_2 construct_max_vertex_2; + Parameter_space_in_x_2 parameter_space_in_x_2; +}; // class Construct_x_monotone_subcurve_2 + + +/* + * This specialization for conic traits makes use of X_monotone_curve_2::trim, + * which is not necessarily available. + */ +template +class Construct_x_monotone_subcurve_2< CGAL::Arr_conic_traits_2< RatKernel, + AlgKernel, + NtTraits > > +{ +public: + typedef CGAL::Arr_conic_traits_2 + ArrTraits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraits::Split_2 Split_2; + typedef typename ArrTraits::Intersect_2 Intersect_2; + typedef typename ArrTraits::Multiplicity Multiplicity; + typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; + typedef typename ArrTraits::Compare_x_2 Compare_x_2; + typedef typename Kernel::FT FT; + typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType + CoordinateType; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename Kernel::Point_2 Kernel_point_2; + + Construct_x_monotone_subcurve_2( const ArrTraits* ) + { + } + + /* + Return the subcurve of curve bracketed by pLeft and pRight. + */ + X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight ); + +}; // class Construct_x_monotone_subcurve_2 for Arr_conic_traits_2 + +template < + typename RatKernel, typename AlgKernel, typename NtTraits, + typename BoundingTraits> +class Construct_x_monotone_subcurve_2> +{ +public: + typedef CGAL::Arr_Bezier_curve_traits_2< + RatKernel, AlgKernel, NtTraits, BoundingTraits> + ArrTraits; + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraits::Split_2 Split_2; + typedef typename ArrTraits::Intersect_2 Intersect_2; + typedef typename ArrTraits::Multiplicity Multiplicity; + typedef typename ArrTraits::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename ArrTraits::Construct_max_vertex_2 Construct_max_vertex_2; + typedef typename ArrTraits::Compare_x_2 Compare_x_2; + typedef typename ArrTraits::Point_2 Point_2; + + Construct_x_monotone_subcurve_2(const ArrTraits* traits_); + + /* + Return the subcurve of curve bracketed by pLeft and pRight. + */ + X_monotone_curve_2 operator()( + const X_monotone_curve_2& curve, const boost::optional& pLeft, + const boost::optional& pRight); + +protected: + const ArrTraits* traits; + Split_2 split_2; + Compare_x_2 compare_x_2; + Arr_compute_y_at_x_2< ArrTraits > compute_y_at_x; + Construct_min_vertex_2 construct_min_vertex_2; + Construct_max_vertex_2 construct_max_vertex_2; +}; // class Construct_x_monotone_subcurve_2 for Arr_conic_traits_2 + +template +class Construct_x_monotone_subcurve_2< + CGAL::Arr_rational_function_traits_2> +{ +public: + typedef CGAL::Arr_rational_function_traits_2 + Traits; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename Traits::Split_2 Split_2; + typedef typename Traits::Intersect_2 Intersect_2; + typedef typename Traits::Multiplicity Multiplicity; + typedef typename Traits::Construct_min_vertex_2 Construct_min_vertex_2; + typedef typename Traits::Construct_max_vertex_2 Construct_max_vertex_2; + typedef typename Traits::Compare_x_2 Compare_x_2; + typedef typename Kernel::FT FT; + typedef typename ArrTraitsAdaptor< Traits >::CoordinateType + CoordinateType; + typedef typename Traits::Point_2 Point_2; + typedef typename Kernel::Point_2 Kernel_point_2; + + Construct_x_monotone_subcurve_2( const Traits* traits_ ); + + /* + Return the subcurve of curve bracketed by pLeft and pRight. + + We assume pLeft and pRight don't lie on the curve and always do a vertical + projection. + */ + X_monotone_curve_2 operator() ( const X_monotone_curve_2& curve, + const boost::optional& pLeft, + const boost::optional& pRight ); + +protected: + const Traits* traits; + Split_2 split_2; + Compare_x_2 compare_x_2; + Arr_compute_y_at_x_2< Traits > compute_y_at_x; + Construct_min_vertex_2 construct_min_vertex_2; + Construct_max_vertex_2 construct_max_vertex_2; +}; // class Construct_x_monotone_subcurve_2 + +/** + Converts between Kernel points and Arrangement points. + + The conversion is not necessarily exact. +*/ +template +class Arr_construct_point_2 +{ + typedef ArrTraits Traits; + typedef typename ArrTraits::Point_2 Point_2; + typedef typename ArrTraitsAdaptor< ArrTraits >::CoordinateType CoordinateType; + typedef typename ArrTraitsAdaptor< ArrTraits >::Kernel Kernel; + typedef typename Kernel::Point_2 Kernel_point_2; + typedef typename Kernel::FT FT; + +public: + Arr_construct_point_2(const Traits* traits_) : traits(traits_) { } + + template + Point_2 operator()(const P& p) + { + return this->operator()(p.x(), p.y()); + } + + template + Point_2 operator()(const T& x, const U& y) + { + return this->operator()(FT{x}, FT{y}); + } + + Point_2 operator()(const Kernel_point_2& pt); + Point_2 operator()(const FT& x, const FT& y); + +protected: + template + Point_2 operator()(const FT& x, const FT& y, const TTraits*); + + template + Point_2 operator()( + const FT& x, const FT& y, + const CGAL::Arr_rational_function_traits_2*); + + const Traits* traits; +}; + +class Find_nearest_edge_base : public GraphicsSceneMixin +{ +public: + /*! Destructor (virtual) */ + virtual ~Find_nearest_edge_base() {} +}; + +template +class Find_nearest_edge : public Find_nearest_edge_base +{ +public: // typedefs + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 ArrTraits; + typedef Compute_squared_distance_2< ArrTraits > Point_curve_distance; + typedef typename ArrTraits::X_monotone_curve_2 X_monotone_curve_2; + typedef typename ArrTraitsAdaptor::Kernel Kernel; + typedef typename Kernel::Point_2 Point_2; + typedef typename Arrangement::Face_const_handle Face_const_handle; + typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; + typedef typename Arrangement::Ccb_halfedge_const_circulator + Ccb_halfedge_const_circulator; + +public: + /*! constructor */ + Find_nearest_edge( Arrangement* arr_ ) : + Find_nearest_edge_base( ), + arr( arr_ ) + { } + + /*! Destructor (virtual) */ + virtual ~Find_nearest_edge() {} + +public: // member methods + Halfedge_const_handle operator()( const Point_2& queryPt ); + + virtual void setScene( QGraphicsScene* scene_ ) + { + this->pointCurveDistance.setScene( scene_ ); + Find_nearest_edge_base::setScene( scene_ ); + } + +protected: // member methods + Face_const_handle getFace( const CGAL::Object& obj ); + +protected: // member fields + Arrangement* arr; + Point_curve_distance pointCurveDistance; + +}; // class Find_nearest_edge + +template +class Insert_curve +{ +public: + typedef Arr_ Arrangement; + typedef typename Arrangement::Geometry_traits_2 ArrTraits; + typedef typename ArrTraits::Curve_2 Curve_2; + + void operator()(Arrangement*, const Curve_2&); +}; + +// free functions gathered here to speed up compilation of other files +// specializing once in one file is better than in multiple files +CGAL::Object createArrangement(demo_types::TraitsType); +void deleteArrangement(demo_types::TraitsType, const CGAL::Object&); +CGAL::Object makeOverlayArrangement(const std::vector&); +void insertCurve( + demo_types::TraitsType, const CGAL::Object& arr, const CGAL::Object& curve); + +#endif // CGAL_ARRANGEMENTS_DEMO_UTILS_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.cpp index 9e94e099d9c..b2a01a81532 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "VerticalRayGraphicsItem.h" @@ -29,6 +30,7 @@ void VerticalRayGraphicsItem::paint( QPainter* painter, QWidget* /* widget */ ) { QPen rayPen( this->m_color, this->m_width ); + rayPen.setCosmetic(true); painter->setPen( rayPen ); if ( this->m_source.isNull( ) && this->m_targetY == 0.0 ) diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.h index c937c57ab8f..b730b2a9f3b 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayGraphicsItem.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,7 +7,8 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef VERTICAL_RAY_GRAPHICS_ITEM_H #define VERTICAL_RAY_GRAPHICS_ITEM_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp index 6d1b9c07379..2738e18edce 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,17 +7,228 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "VerticalRayShootCallback.h" +#include "VerticalRayGraphicsItem.h" +#include "ArrangementTypes.h" +#include "ArrangementTypesUtils.h" +#include "CurveGraphicsItem.h" +#include "Utils/PointLocationFunctions.h" +#include "Utils/Utils.h" + +#include +#include + +template +class VerticalRayShootCallback : public VerticalRayShootCallbackBase +{ +public: + typedef VerticalRayShootCallbackBase Superclass; + typedef Arr_ Arrangement; + typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; + typedef typename Arrangement::Face_const_handle Face_const_handle; + typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; + typedef typename Arrangement::Geometry_traits_2 Traits; + + VerticalRayShootCallback(Arrangement* arr_, QObject* parent_); + void reset() override; + void setScene(QGraphicsScene* scene_) override; + void slotModelChanged() override; + void setEdgeWidth(int width) override; + void setEdgeColor(const QColor& color) override; + const QColor& edgeColor() const override; + int edgeWidth() const override; + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent* event) override; + void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override; + void highlightPointLocation(QGraphicsSceneMouseEvent* event); + + Arrangement* arr; + CGAL::Qt::CurveGraphicsItem* highlightedCurves; + VerticalRayGraphicsItem rayGraphicsItem; +}; // class VerticalRayShootCallback VerticalRayShootCallbackBase::VerticalRayShootCallbackBase(QObject* parent_) : - CGAL::Qt::Callback( parent_ ), - shootingUp( true ) -{ } + CGAL::Qt::Callback(parent_), shootingUp(true) +{ +} -void VerticalRayShootCallbackBase::setShootingUp( bool isShootingUp ) +// msvc2015 doesn't play well with polymorphic lambdas +namespace +{ +struct ExplicitLambda +{ + template + void operator()(demo_types::TypeHolder) + { + Arrangement* arr = nullptr; + CGAL::assign(arr, arr_obj); + res = new VerticalRayShootCallback(arr, parent); + } + + VerticalRayShootCallbackBase*& res; + CGAL::Object& arr_obj; + QObject* parent; +}; +} // anonymous namespace + +VerticalRayShootCallbackBase* VerticalRayShootCallbackBase::create( + demo_types::TraitsType tt, CGAL::Object arr_obj, QObject* parent) +{ + VerticalRayShootCallbackBase* res; + ExplicitLambda explicit_lambda{res, arr_obj, parent}; + demo_types::visitArrangementType(tt, explicit_lambda); + return res; +} + +void VerticalRayShootCallbackBase::setShootingUp(bool isShootingUp) { this->shootingUp = isShootingUp; } +template +VerticalRayShootCallback::VerticalRayShootCallback( + Arrangement* arr_, QObject* parent_) : + VerticalRayShootCallbackBase(parent_), + arr(arr_), + highlightedCurves(new CGAL::Qt::CurveGraphicsItem()) +{ + this->rayGraphicsItem.setZValue(100); + + this->highlightedCurves->setEdgeColor(this->rayGraphicsItem.color()); + this->highlightedCurves->setVertexColor(this->rayGraphicsItem.color()); + this->highlightedCurves->setZValue(100); + + QObject::connect( + this, SIGNAL(modelChanged()), this->highlightedCurves, + SLOT(modelChanged())); + QObject::connect( + this, SIGNAL(modelChanged()), this, SLOT(slotModelChanged())); +} + +template +void VerticalRayShootCallback::setEdgeWidth( int width ) +{ + this->highlightedCurves->setEdgeWidth( width ); + this->rayGraphicsItem.setWidth( width ); +} + +template +void VerticalRayShootCallback::setEdgeColor( const QColor& color ) +{ + this->highlightedCurves->setEdgeColor( color ); + this->rayGraphicsItem.setColor( color ); +} + +template +const QColor& VerticalRayShootCallback::edgeColor( ) const +{ + return this->highlightedCurves->edgeColor( ); +} + +template +int VerticalRayShootCallback::edgeWidth( ) const +{ + return this->highlightedCurves->edgeWidth( ); +} + +template +void VerticalRayShootCallback::setScene(QGraphicsScene* scene_) +{ + CGAL::Qt::Callback::setScene(scene_); + this->highlightedCurves->setScene(scene_); + if (scene_) + { + this->scene->addItem(this->highlightedCurves); + this->scene->addItem(&this->rayGraphicsItem); + } +} + +template +void VerticalRayShootCallback::slotModelChanged() +{ +} + +template +void VerticalRayShootCallback::reset() +{ + this->rayGraphicsItem.reset(); + this->highlightedCurves->clear(); + Q_EMIT modelChanged(); +} + +template +void VerticalRayShootCallback::mousePressEvent( + QGraphicsSceneMouseEvent* event) +{ + this->highlightPointLocation(event); +} + +template +void VerticalRayShootCallback::mouseMoveEvent( + QGraphicsSceneMouseEvent* /* event */) +{ +} + +template +void VerticalRayShootCallback::highlightPointLocation( + QGraphicsSceneMouseEvent* event) +{ + this->highlightedCurves->clear(); + QPointF queryQPt = event->scenePos(); + + CGAL::Object pointLocationResult; + if (this->shootingUp) + pointLocationResult = + PointLocationFunctions{}.rayShootUp(arr, queryQPt); + else + pointLocationResult = + PointLocationFunctions{}.rayShootDown(arr, queryQPt); + + if (pointLocationResult.is_empty()) { return; } + + QRectF viewportRect = this->viewportRect(); + qreal y2; + if (this->shootingUp) + { // +y in Qt is towards the bottom + y2 = viewportRect.bottom(); + } + else + { + y2 = viewportRect.top(); + } + Face_const_handle unboundedFace; + Halfedge_const_handle halfedge; + Vertex_const_handle vertex; + if (CGAL::assign(unboundedFace, pointLocationResult)) + { + this->rayGraphicsItem.setSource(queryQPt); + this->rayGraphicsItem.setTargetY(y2); + this->rayGraphicsItem.setIsInfinite(true); + } + else if (CGAL::assign(halfedge, pointLocationResult)) + { + this->highlightedCurves->insert(halfedge->curve()); + + // draw a ray from the clicked point to the hit curve + Arr_compute_y_at_x_2 compute_y_at_x_2{arr->traits()}; + compute_y_at_x_2.setScene(this->getScene()); + double yApprox = compute_y_at_x_2.approx(halfedge->curve(), queryQPt.x()); + this->rayGraphicsItem.setSource(queryQPt); + this->rayGraphicsItem.setTargetY(yApprox); + this->rayGraphicsItem.setIsInfinite(false); + } + else if (CGAL::assign(vertex, pointLocationResult)) + { + if (!vertex->is_at_open_boundary()) + { + auto pt = vertex->point(); + this->highlightedCurves->insert(pt); + } + } + + Q_EMIT modelChanged(); +} diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.h b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.h index 00b841f2d6f..3cd5107b780 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.h +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/VerticalRayShootCallback.h @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,32 +7,32 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #ifndef VERTICAL_RAY_SHOOT_CALLBACK_H #define VERTICAL_RAY_SHOOT_CALLBACK_H -#include -#include -#include -#include -#include -#include -#include "CurveGraphicsItem.h" -#include -#include -#include -#include -#include -#include - #include "Callback.h" -#include "Utils.h" -#include "VerticalRayGraphicsItem.h" +#include +namespace demo_types +{ +enum class TraitsType : int; +} + +class QGraphicsSceneMouseEvent; +class QGraphicsScene; + +/* + * Supports visualization of vertical ray shooting on arrangements. + */ class VerticalRayShootCallbackBase : public CGAL::Qt::Callback { public: + static VerticalRayShootCallbackBase* + create(demo_types::TraitsType, CGAL::Object arr_obj, QObject* parent); + void setShootingUp( bool isShootingUp ); virtual void setEdgeWidth( int width ) = 0; @@ -42,406 +42,7 @@ public: protected: VerticalRayShootCallbackBase( QObject* parent_ ); - using Callback::scene; bool shootingUp; }; // class VerticalRayShootCallbackBase -/* - * Supports visualization of vertical ray shooting on arrangements. - * - * The template parameter is a CGAL::Arrangement_with_history_2 of some type. - */ -template < typename Arr_ > -class VerticalRayShootCallback : public VerticalRayShootCallbackBase -{ -public: - typedef VerticalRayShootCallbackBase Superclass; - typedef Arr_ Arrangement; - typedef typename Arrangement::Halfedge_handle Halfedge_handle; - typedef typename Arrangement::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement::Halfedge_iterator Halfedge_iterator; - typedef typename Arrangement::Face_handle Face_handle; - typedef typename Arrangement::Face_const_handle Face_const_handle; - typedef typename Arrangement::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement::Halfedge_around_vertex_const_circulator - Halfedge_around_vertex_const_circulator; - typedef typename Arrangement::Geometry_traits_2 Traits; - typedef typename Arrangement::Curve_handle Curve_handle; - typedef typename Arrangement::Originating_curve_iterator - Originating_curve_iterator; - typedef typename Arrangement::Induced_edge_iterator Induced_edge_iterator; - typedef typename Arrangement::Ccb_halfedge_const_circulator - Ccb_halfedge_const_circulator; - typedef typename Arrangement::Hole_const_iterator Hole_const_iterator; - typedef typename Traits::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Traits::Intersect_2 Intersect_2; - typedef typename Traits::Multiplicity Multiplicity; - typedef typename ArrTraitsAdaptor< Traits >::Kernel Kernel; - typedef typename ArrTraitsAdaptor< Traits >::CoordinateType CoordinateType; - typedef typename Kernel::Point_2 Kernel_point_2; - typedef typename Traits::Point_2 Point_2; - typedef std::pair< typename Traits::Point_2, Multiplicity > - IntersectionResult; - typedef typename Kernel::Segment_2 Segment_2; - typedef typename Kernel::FT FT; - typedef typename CGAL::Arr_trapezoid_ric_point_location< Arrangement > - TrapezoidPointLocationStrategy; - typedef typename CGAL::Arr_simple_point_location< Arrangement > - SimplePointLocationStrategy; - typedef typename CGAL::Arr_walk_along_line_point_location< Arrangement > - Walk_pl_strategy; - typedef typename CGAL::Arr_landmarks_point_location< Arrangement > - LandmarksPointLocationStrategy; - - VerticalRayShootCallback( Arrangement* arr_, QObject* parent_ ); - void reset( ); - void setScene( QGraphicsScene* scene_ ); - - void slotModelChanged( ); - - virtual void setEdgeWidth( int width ) - { - this->highlightedCurves->setEdgeWidth( width ); - this->rayGraphicsItem.setWidth( width ); - } - - virtual void setEdgeColor( const QColor& color ) - { - this->highlightedCurves->setEdgeColor( color ); - this->rayGraphicsItem.setColor( color ); - } - - virtual const QColor& edgeColor( ) const - { - return this->highlightedCurves->edgeColor( ); - } - - virtual int edgeWidth( ) const - { - return this->highlightedCurves->edgeWidth( ); - } - -protected: - void mousePressEvent( QGraphicsSceneMouseEvent *event ); - void mouseMoveEvent( QGraphicsSceneMouseEvent *event ); - void highlightPointLocation( QGraphicsSceneMouseEvent *event ); - Face_const_handle getFace( const CGAL::Object& o ); - CGAL::Object rayShootUp( const Kernel_point_2& point ); - CGAL::Object rayShootUp( const Kernel_point_2& point, CGAL::Tag_true ); - CGAL::Object rayShootUp( const Kernel_point_2& point, CGAL::Tag_false ); - CGAL::Object rayShootDown( const Kernel_point_2& point ); - CGAL::Object rayShootDown( const Kernel_point_2& point, CGAL::Tag_true ); - CGAL::Object rayShootDown( const Kernel_point_2& point, CGAL::Tag_false ); - - using Superclass::scene; - using Superclass::shootingUp; - Traits traits; - Arrangement* arr; - Intersect_2 intersectCurves; - CGAL::Qt::Converter< Kernel > convert; - CGAL::Object pointLocationStrategy; - CGAL::Qt::CurveGraphicsItem< Traits >* highlightedCurves; - QGraphicsLineItem* activeRay; - Kernel_point_2 queryPt; - Arr_construct_point_2< Traits > toArrPoint; - VerticalRayGraphicsItem rayGraphicsItem; -}; // class VerticalRayShootCallback - -template < typename Arr_ > -VerticalRayShootCallback< Arr_ >:: -VerticalRayShootCallback( Arrangement* arr_, QObject* parent_ ): - VerticalRayShootCallbackBase( parent_ ), - arr( arr_ ), - intersectCurves( this->traits.intersect_2_object( ) ), - pointLocationStrategy( CGAL::make_object( new Walk_pl_strategy( *arr_ ) ) ), - highlightedCurves( new CGAL::Qt::CurveGraphicsItem< Traits >( ) ), - activeRay( new QGraphicsLineItem ) -{ - this->rayGraphicsItem.setZValue( 100 ); - - this->highlightedCurves->setEdgeColor( this->rayGraphicsItem.color( ) ); - this->highlightedCurves->setVertexColor( this->rayGraphicsItem.color( ) ); - this->highlightedCurves->setZValue( 100 ); - - QObject::connect( this, SIGNAL( modelChanged( ) ), - this->highlightedCurves, SLOT( modelChanged( ) ) ); - QObject::connect( this, SIGNAL( modelChanged( ) ), - this, SLOT( slotModelChanged( ) ) ); -} - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >::setScene( QGraphicsScene* scene_ ) -{ - this->scene = scene_; - this->highlightedCurves->setScene( scene_ ); - if ( this->scene ) - { - this->scene->addItem( this->highlightedCurves ); - this->scene->addItem( this->activeRay ); - this->scene->addItem( &this->rayGraphicsItem ); - } -} - - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >::slotModelChanged( ) -{ - this->activeRay->update( ); -} - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >::reset( ) -{ - this->activeRay->setLine( 0, 0, 0, 0 ); - this->rayGraphicsItem.reset( ); - this->highlightedCurves->clear( ); - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >:: -mousePressEvent( QGraphicsSceneMouseEvent* event ) -{ - this->highlightPointLocation( event ); -} - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >:: -mouseMoveEvent(QGraphicsSceneMouseEvent* /* event */) -{ } - -template < typename Arr_ > -void VerticalRayShootCallback< Arr_ >:: -highlightPointLocation( QGraphicsSceneMouseEvent* event ) -{ - this->highlightedCurves->clear( ); - this->queryPt = this->convert( event->scenePos( ) ); - CGAL::Object pointLocationResult; - if ( this->shootingUp ) - { - pointLocationResult = this->rayShootUp( this->queryPt ); - } - else - { - pointLocationResult = this->rayShootDown( this->queryPt ); - } - if ( pointLocationResult.is_empty( ) ) - { - return; - } - - QRectF viewportRect = this->viewportRect( ); - FT y2; - if ( this->shootingUp ) - { // +y in Qt is towards the bottom - y2 = FT( viewportRect.bottom( ) ); - } - else - { - y2 = FT( viewportRect.top( ) ); - } - Face_const_handle unboundedFace; - Halfedge_const_handle halfedge; - Vertex_const_handle vertex; - if ( CGAL::assign( unboundedFace, pointLocationResult ) ) - { - Kernel_point_2 p2( FT( this->queryPt.x( ) ), y2 ); - Segment_2 lineSegment( this->queryPt, p2 ); - // QLineF qLineSegment = this->convert( lineSegment ); - // this->activeRay->setLine( qLineSegment ); - this->rayGraphicsItem.setSource( event->scenePos( ) ); - this->rayGraphicsItem.setTargetY( CGAL::to_double( y2 ) ); - this->rayGraphicsItem.setIsInfinite( true ); - } - else if ( CGAL::assign( halfedge, pointLocationResult ) ) - { - this->highlightedCurves->insert( halfedge->curve( ) ); - - // draw a ray from the clicked point to the hit curve - Arr_compute_y_at_x_2< Traits > compute_y_at_x_2; - compute_y_at_x_2.setScene( this->getScene( ) ); - CoordinateType x( this->queryPt.x( ) ); - double yApprox = - CGAL::to_double( compute_y_at_x_2.approx( halfedge->curve( ), x ) ); - FT yInt( yApprox ); - Kernel_point_2 p2( this->queryPt.x( ), yInt ); - Segment_2 seg( this->queryPt, p2 ); - // QLineF qseg = this->convert( seg ); - // this->activeRay->setLine( qseg ); - this->rayGraphicsItem.setSource( event->scenePos( ) ); - this->rayGraphicsItem.setTargetY( CGAL::to_double( yInt ) ); - this->rayGraphicsItem.setIsInfinite( false ); - } - else if ( CGAL::assign( vertex, pointLocationResult ) ) - { - if ( ! vertex->is_at_open_boundary( ) ) - { - Point_2 pt = vertex->point( ); - this->highlightedCurves->insert( pt ); - } - } - - Q_EMIT modelChanged( ); -} - -template < typename Arr_ > -typename VerticalRayShootCallback< Arr_ >::Face_const_handle -VerticalRayShootCallback< Arr_ >::getFace( const CGAL::Object& obj ) -{ - Face_const_handle f; - if ( CGAL::assign( f, obj ) ) - return f; - - Halfedge_const_handle he; - if (CGAL::assign( he, obj )) - return (he->face( )); - - Vertex_const_handle v; - CGAL_assertion(CGAL::assign( v, obj )); - CGAL::assign( v, obj ); - if ( v->is_isolated( ) ) - return v->face( ); - Halfedge_around_vertex_const_circulator eit = v->incident_halfedges( ); - return (eit->face( )); -} - -template < typename Arr_ > -CGAL::Object -VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt ) -{ - typename Supports_landmarks< Arrangement >::Tag supportsLandmarks; - return this->rayShootUp( pt, supportsLandmarks ); -} - -template < typename Arr_ > -CGAL::Object VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt, - CGAL::Tag_true ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - LandmarksPointLocationStrategy* landmarksStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->ray_shoot_up( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->ray_shoot_up( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->ray_shoot_up( point ); - } - else if ( CGAL::assign( landmarksStrategy, this->pointLocationStrategy ) ) - { - // pointLocationResult = landmarksStrategy->locate( point ); - std::cerr << "Warning: landmarks point location strategy doesn't support ray shooting" << std::endl; - return CGAL::Object( ); - } - return pointLocationResult; -} - -template < typename Arr_ > -CGAL::Object VerticalRayShootCallback< Arr_ >::rayShootUp( const Kernel_point_2& pt, - CGAL::Tag_false ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->ray_shoot_up( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->ray_shoot_up( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->ray_shoot_up( point ); - } - else - { - std::cout<<"Didn't find the right strategy\n"; - } - - return pointLocationResult; -} - -template < typename Arr_ > -CGAL::Object -VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt ) -{ - typename Supports_landmarks< Arrangement >::Tag supportsLandmarks; - return this->rayShootDown( pt, supportsLandmarks ); -} - -template < typename Arr_ > -CGAL::Object -VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt, CGAL::Tag_true ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - LandmarksPointLocationStrategy* landmarksStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->ray_shoot_down( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->ray_shoot_down( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->ray_shoot_down( point ); - } - else if ( CGAL::assign( landmarksStrategy, this->pointLocationStrategy ) ) - { - // pointLocationResult = landmarksStrategy->locate( point ); - std::cerr << "Warning: landmarks point location strategy doesn't support ray shooting" << std::endl; - return CGAL::Object( ); - } - return pointLocationResult; -} - -template < typename Arr_ > -CGAL::Object -VerticalRayShootCallback< Arr_ >::rayShootDown( const Kernel_point_2& pt, CGAL::Tag_false ) -{ - CGAL::Object pointLocationResult; - Walk_pl_strategy* walkStrategy; - TrapezoidPointLocationStrategy* trapezoidStrategy; - SimplePointLocationStrategy* simpleStrategy; - - Point_2 point = this->toArrPoint( pt ); - - if ( CGAL::assign( walkStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = walkStrategy->ray_shoot_down( point ); - } - else if ( CGAL::assign( trapezoidStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = trapezoidStrategy->ray_shoot_down( point ); - } - else if ( CGAL::assign( simpleStrategy, this->pointLocationStrategy ) ) - { - pointLocationResult = simpleStrategy->ray_shoot_down( point ); - } - return pointLocationResult; -} - #endif // VERTICAL_RAY_SHOOT_CALLBACK_H diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/arrangement_2.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/arrangement_2.cpp index c497c474d1c..35d589585d8 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/arrangement_2.cpp +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/arrangement_2.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Tel-Aviv University (Israel). +// Copyright (c) 2012, 2020 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -7,17 +7,23 @@ // $Id$ // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial // -// Author(s) : Alex Tsui +// Author(s): Alex Tsui +// Ahmed Essam #include "ArrangementDemoWindow.h" #include -int main( int argc, char* argv[] ) +int main(int argc, char* argv[]) { - QApplication app( argc, argv ); + QApplication app(argc, argv); + QCoreApplication::setOrganizationName("CGAL"); + QCoreApplication::setApplicationName("2D Arrangements Demo"); + + // Import resources from libCGAL (Qt5). + CGAL_QT_INIT_RESOURCES; ArrangementDemoWindow demoWindow; - demoWindow.show( ); + demoWindow.show(); - return app.exec( ); + return app.exec(); } diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/circle.arr b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/circle.arr new file mode 100644 index 00000000000..318efb2fc12 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/circle.arr @@ -0,0 +1,54 @@ +# BEGIN ARRANGEMENT +# number_of_vertices +4 +# number_of_edges +4 +# number_of_faces +2 +# BEGIN VERTICES +0 2 0 +0 3 0 +1 2 0 +1 3 0 +# END VERTICES +# BEGIN EDGES +0 1 0 0 +1 3 0 0 +3 2 1 0 +2 0 1 0 +# END EDGES +# BEGIN FACES +# BEGIN FACE +1 0 +# number_of_outer_ccbs +0 +# number_of_inner_ccbs +1 +# halfedges_on_inner_ccb +4 +0 2 4 6 +# number_of_isolated_vertices +0 +# END FACE +# BEGIN FACE +1 1 +# number_of_outer_ccbs +1 +# halfedges_on_outer_ccb +4 +1 7 5 3 +# number_of_inner_ccbs +0 +# number_of_isolated_vertices +0 +# END FACE +# END FACES +# END ARRANGEMENT +# BEGIN CURVES +# number_of_curves +1 +P[2(0,P[2(0,6)(2,1)])(2,P[0(0,1)])] +# induced_edges +0 + +# END CURVES diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/ellipse.arr b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/ellipse.arr new file mode 100644 index 00000000000..beee3225190 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/ellipse.arr @@ -0,0 +1,54 @@ +# BEGIN ARRANGEMENT +# number_of_vertices +4 +# number_of_edges +4 +# number_of_faces +2 +# BEGIN VERTICES +0 2 0 +0 3 0 +1 2 0 +1 3 0 +# END VERTICES +# BEGIN EDGES +0 1 0 0 +1 3 0 0 +3 2 1 0 +2 0 1 0 +# END EDGES +# BEGIN FACES +# BEGIN FACE +1 0 +# number_of_outer_ccbs +0 +# number_of_inner_ccbs +1 +# halfedges_on_inner_ccb +4 +0 2 4 6 +# number_of_isolated_vertices +0 +# END FACE +# BEGIN FACE +1 1 +# number_of_outer_ccbs +1 +# halfedges_on_outer_ccb +4 +1 7 5 3 +# number_of_inner_ccbs +0 +# number_of_isolated_vertices +0 +# END FACE +# END FACES +# END ARRANGEMENT +# BEGIN CURVES +# number_of_curves +1 +P[2(0,P[2(0,8)(2,3)])(2,P[0(0,5)])] +# induced_edges +0 + +# END CURVES diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/hyperbola.arr b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/hyperbola.arr new file mode 100644 index 00000000000..1a64f73961d --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/data/algebraic/hyperbola.arr @@ -0,0 +1,54 @@ +# BEGIN ARRANGEMENT +# number_of_vertices +4 +# number_of_edges +4 +# number_of_faces +2 +# BEGIN VERTICES +0 2 0 +0 3 0 +1 2 0 +1 3 0 +# END VERTICES +# BEGIN EDGES +0 1 0 0 +1 3 0 0 +3 2 1 0 +2 0 1 0 +# END EDGES +# BEGIN FACES +# BEGIN FACE +1 0 +# number_of_outer_ccbs +0 +# number_of_inner_ccbs +1 +# halfedges_on_inner_ccb +4 +0 2 4 6 +# number_of_isolated_vertices +0 +# END FACE +# BEGIN FACE +1 1 +# number_of_outer_ccbs +1 +# halfedges_on_outer_ccb +4 +1 7 5 3 +# number_of_inner_ccbs +0 +# number_of_isolated_vertices +0 +# END FACE +# END FACES +# END ARRANGEMENT +# BEGIN CURVES +# number_of_curves +1 +P[2(0,P[2(0,8)(2,1)])(2,P[0(0,1)])] +# induced_edges +0 + +# END CURVES diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/delete.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/delete.xpm deleted file mode 100644 index 57d0b777703..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/delete.xpm +++ /dev/null @@ -1,42 +0,0 @@ -/* XPM */ -static const char *delete_xpm[] = { -/* columns rows colors chars-per-pixel */ -"32 32 4 1", -" c opaque", -". c navy", -"X c #c0c0c0", -"o c None", -/* pixels */ -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"ooooooooooo.oooooo.ooooooooooooo", -"ooooooooooo.oooooo.ooooooooooooo", -"oooooooooo..oooooo..oooooooooooo", -"oooooooooo..oooooo..oooooooooooo", -"oooooooooo..oooooo..oooooooooooo", -"oooooooooo..oooooo..oooooooooooo", -"oooooooooo...oooo...oooooooooooo", -"ooooooooooo...oo...ooooooooooooo", -"oooooooooooo......oooooooooooooo", -"ooooooooooooo....ooooooooooooooo", -"oooooooooooo......oooooooooooooo", -"ooooooooooo........ooooooooooooo", -"oooooooooo....oo....oooooooooooo", -"oooooooo......oo......oooooooooo", -"oooooo..oooo..oo..oooo..oooooooo", -"ooooo..ooooo..oo..ooooo..ooooooo", -"ooooo..ooooo..oo..ooooo..ooooooo", -"ooooo..oooo..oooo..oooo..ooooooo", -"oooooo..oo..oooooo..oo..oooooooo", -"ooooooo....oooooooo....ooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo" -}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/insert.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/insert.xpm deleted file mode 100644 index 41945ca8893..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/insert.xpm +++ /dev/null @@ -1,42 +0,0 @@ -/* XPM */ -static const char *insert_xpm[] = { -/* columns rows colors chars-per-pixel */ -"32 32 4 1", -" c opaque", -". c navy", -"X c #c0c0c0", -"o c None", -/* pixels */ -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"ooooo......................ooooo", -"ooooo......................ooooo", -"ooooo......................ooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"oooooooooooo.......ooooooooooooo", -"ooooo......................ooooo", -"ooooo......................ooooo", -"ooooo......................ooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo" -}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/merge.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/merge.xpm deleted file mode 100644 index c0c209f7ed3..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/merge.xpm +++ /dev/null @@ -1,46 +0,0 @@ -/* XPM */ -const char *merge_xpm[] = { -/* columns rows colors chars-per-pixel */ -"32 32 4 1", -" c opaque", -". c navy", -"X c #c0c0c0", -"o c None", -/* pixels */ -"oooooooooooooooooooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"ooo oooo", -"ooo oooo", -"oooooooooooooo ooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooo oo oo ooooooooooo", -"ooooooooooo o o oooooooooooo", -"oooooooooooo ooooooooooooo", -"ooooooooooooo oooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"ooo oooo", -"ooo oooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -}; - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/split.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/split.xpm deleted file mode 100644 index 923a7bcab48..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/split.xpm +++ /dev/null @@ -1,46 +0,0 @@ -/* XPM */ -const const char *split_xpm[] = { -/* columns rows colors chars-per-pixel */ -"32 32 4 1", -" c opaque", -". c navy", -"X c #c0c0c0", -"o c None", -/* pixels */ -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"ooo oooo", -"ooo oooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"oooooooooo oo oo ooooooooooo", -"ooooooooooo o o oooooooooooo", -"oooooooooooo ooooooooooooo", -"ooooooooooooo oooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooo ooooooooooooooo", -"ooo oooo", -"ooo oooo", -"oooooooooooooo ooooooooooooooo", -"ooooooooooooooo oooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -"oooooooooooooooooooooooooooooooo", -}; - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/about.html b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/about.html new file mode 100644 index 00000000000..8e168cc7b72 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/about.html @@ -0,0 +1,30 @@ + + +2D Arrangements Demo + + +

    2D Arrangements Demo

    +
    +This program demonstrates the use of CGAL's 2D Arrangements package.
    +It enables the user to create and manipulate arrangements of: +
      +
    • Boundeed line segments.
    • +
    • Polylines.
    • +
    • Unbounded linear curves.
    • +
    • Conic curves.
    • +
    • Algebraic curves.
    • +
    • Bezier curves.
    • +
    • Rational functions.
    • +
    +For each of these arrangements the following operations are supported: +
      +
    • Curve insertion.
    • +
    • Curve deletion.
    • +
    • Point location queries.
    • +
    • Vertical ray shooting (up/down).
    • +
    • Splitting.
    • +
    • Merging.
    • +
    • Lower/upper envelopes.
    • +
    + + diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_arrow_down.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/arrow_down.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_arrow_down.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/arrow_down.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_arrow_up.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/arrow_up.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_arrow_up.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/arrow_up.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/blue_icon.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/blue_icon.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/blue_icon.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/blue_icon.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_colors.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/colors.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_colors.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/colors.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/conic.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/conic.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_3points.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_3points.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_3points.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_3points.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_5points.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_5points.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_5points.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_5points.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_circle.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_circle.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_circle.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_circle.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_ellipse.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_ellipse.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_ellipse.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_ellipse.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_line.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_line.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_line.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_line.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_ray.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_ray.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_ray.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_ray.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_segment.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_segment.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_conic_segment.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_segment.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/conic_types.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_types.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/conic_types.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/conic_types.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_delete.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/delete.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_delete.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/delete.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_delete.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/delete.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_delete.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/delete.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/draw.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/draw.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/draw.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/draw.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/equation.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/equation.xpm new file mode 100644 index 00000000000..ea5c38d920a --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/equation.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static char *equation_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 2 1", +" c None", +". c navy", +/* pixels */ +" ", +" ", +" ", +" ", +" ........................ ", +" ....................... ", +" ..... .... ", +" ..... .... ", +" ..... .... ", +" ..... .. ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" .... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... ", +" ..... .. ", +" ..... .... ", +" ..... .... ", +" ....................... ", +" ........................ ", +" ", +" ", +" ", +" " +}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_fill.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/fill.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_fill.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/fill.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/green_icon.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/green_icon.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/green_icon.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/green_icon.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapgrid.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/grid.xpm similarity index 97% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapgrid.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/grid.xpm index f9d8355aab0..baae0a06852 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapgrid.xpm +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/grid.xpm @@ -1,5 +1,5 @@ /* XPM */ -static const char *snapgrid_xpm[] = { +static const char *grid[] = { /* width height ncolors chars_per_pixel */ "32 32 2 1", /* colors */ diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/hand.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/hand.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/hand.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/hand.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_insert.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/insert.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_insert.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/insert.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_insert.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/insert.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_insert.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/insert.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/lower_env_xpm.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/lower_env_xpm.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/lower_env_xpm.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/lower_env_xpm.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/lower_env_xpm.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/lower_env_xpm.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/lower_env_xpm.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/lower_env_xpm.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_merge.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/merge.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_merge.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/merge.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_merge.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/merge.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_merge.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/merge.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/none.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/none.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/none.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/none.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pink_icon.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pink_icon.xpm new file mode 100644 index 00000000000..550f9bcf33c --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pink_icon.xpm @@ -0,0 +1,23 @@ +/* XPM */ +const char* blue_icon[] = { +/* columns rows colors chars-per-pixel */ + "16 16 2 1", + "g c #FFC0CB", + ". c None", +/* pixels */ + "................", + "................", + "..gggggggggggg..", + "..gggggggggggg..", + "..gggggggggggg..", + "..ggg......ggg..", + "..ggg......ggg..", + "..ggg......ggg..", + "..ggg......ggg..", + "..ggg......ggg..", + "..ggg......ggg..", + "..gggggggggggg..", + "..gggggggggggg..", + "..gggggggggggg..", + "................", + "................"}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/po.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/po.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/po.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/po.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_pointlocation.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pointlocation.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_pointlocation.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pointlocation.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_pointlocation.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pointlocation.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_pointlocation.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/pointlocation.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/points.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/points.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/points.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/points.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/polyline.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/polyline.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/polyline.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/polyline.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/ray_shooting.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/ray_shooting.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/ray_shooting.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/ray_shooting.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/ray_shooting2.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/ray_shooting2.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/ray_shooting2.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/ray_shooting2.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot_down.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot_down.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot_down.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot_down.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot_up.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot_up.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_rayshoot_up.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/rayshoot_up.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/red_icon.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/red_icon.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/red_icon.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/red_icon.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/snap.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snap.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/snap.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snap.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/grid.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snap_to_grid.xpm similarity index 77% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/grid.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snap_to_grid.xpm index a61b8a718d3..342a95f3674 100644 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/grid.xpm +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snap_to_grid.xpm @@ -8,11 +8,11 @@ const const char * grid_xpm[] = { "....+.......+....", "....+.......+....", "....+.......+....", -"....+.......+....", -"....+.......+....", -"+++++++++++++++++", -"....+.......+....", -"....+.......+....", +".. @+@ .....+....", +"..@ + @.....+....", +"++++ ++++++++++++", +"..@ + @.....+....", +".. @+@ .....+....", "....+.......+....", "....+.......+....", "....+.......+....", diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapgrid.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapgrid.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapgrid.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapgrid.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapgrid.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapgrid.xpm new file mode 100644 index 00000000000..a9006139562 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapgrid.xpm @@ -0,0 +1,43 @@ +/* XPM */ +static const char *snapgrid_xpm[] = { +/* width height ncolors chars_per_pixel */ +"32 32 4 1", +/* colors */ +" c #008080", +"+ c #FFFF00", +"x c red", +". c None", +/* pixels */ +"................................", +"................................", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +".. ..", +"..... xx.... ....xx ...... .....", +"..... xx.... ....xx ...... .....", +"..... .xxx.. ...xx. ...... .....", +"..... ..xxx+++xxx.. ...... .....", +"..... ..+xx. .xx+.. ...... .....", +"..... .++.xx xx.++. ...... .....", +".. ++ x ++ ..", +"..... .++.xx xxh++. ...... .....", +"..... ..+xx. .xx+.. ...... .....", +"..... ..xxx+++xxx.. ...... .....", +"..... .xx... ...xx. ...... .....", +"..... xx.... ....xx ...... .....", +"..... xx.... ....xx ...... .....", +".. ..", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +".. ..", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"..... ...... ...... ...... .....", +"................................", +"................................" +}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapvertex.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapvertex.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapvertex.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapvertex.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapvertex.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapvertex.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_snapvertex.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/snapvertex.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_split.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/split.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_split.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/split.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_split.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/split.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_split.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/split.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/upper_env_xpm.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/upper_env_xpm.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/upper_env_xpm.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/upper_env_xpm.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/upper_env_xpm.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/upper_env_xpm.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/upper_env_xpm.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/upper_env_xpm.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/voronoi.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/voronoi.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/voronoi.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/voronoi.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/yellow_icon.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/yellow_icon.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/yellow_icon.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/yellow_icon.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomin.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomin.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomin.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomin.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomin.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomin.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomin.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomin.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomout.bmp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomout.bmp similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomout.bmp rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomout.bmp diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomout.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomout.xpm similarity index 100% rename from Arrangement_on_surface_2/demo/Arrangement_on_surface_2/icons/demo_zoomout.xpm rename to Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomout.xpm diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomreset.xpm b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomreset.xpm new file mode 100644 index 00000000000..bbda98c20d7 --- /dev/null +++ b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/resources/icons/zoomreset.xpm @@ -0,0 +1,47 @@ +/* XPM */ +static const char *zoomin_xpm[] = { +/* width height ncolors chars_per_pixel */ +"32 32 8 1", +/* colors */ +" c #000000", +". c #C0C0C0", +"X c #008080", +"o c #FF0000", +"O c #808080", +"+ c #000080", +"# c #0000FF", +"@ c None", +/* pixels */ +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@O O@@@@@@@@@@@@@@@", +"@@@@@@@@O O...O O@@@@@@@@@@@@@", +"@@@@@@@ O..@@@..O @@@@@@@@@@@@", +"@@@@@@ O..@@@@@@@..O @@@@@@@@@@@", +"@@@@@O ..@@@@@@@@@.. O@@@@@@@@@@", +"@@@@@ O.@@ooooo@@@@.O @@@@@@@@@@", +"@@@@O .@@oo@@@ooo@@@. O@@@@@@@@@", +"@@@@ O.@@o@@@@@@o@@@.O @@@@@@@@@", +"@@@@ .@@oo@@@@@@o@@@@. @@@@@@@@@", +"@@@@ .@@oo@@@@o@o@o@@. @@@@@@@@@", +"@@@@ .@@oo@@@@o@o@o@@. @@@@@@@@@", +"@@@@ O.@oo@@@@@ooo@@.O @@@@@@@@@", +"@@@@O .@@ooo@@@@@@@@. O@@@@@@@@@", +"@@@@@ O.@@@oooo@@@@.O @@@@@@@@@@", +"@@@@@O ..@@@@@@@@@.. O@@@@@@@@@@", +"@@@@@@ O..@@@@@@@..O +@@@@@@@@@@", +"@@@@@@@ O..@@@..O ##+@@@@@@@@@", +"@@@@@@@@O O...O O+X##+@@@@@@@@", +"@@@@@@@@@@O O@@@+X##+@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@+X##+@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@+X##+@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@+X##+@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@+X##+@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@+X+@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@+@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", +"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" +}; diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/CMakeLists.txt b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/CMakeLists.txt deleted file mode 100644 index 4c9fdacfcc5..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_executable( Test Test.cpp ) -add_executable( TestRayPL TestRayPL.cpp ) -add_executable( TestAlgebraic TestAlgebraic.cpp ) - diff --git a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/Test.cpp b/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/Test.cpp deleted file mode 100644 index e8966bc2e20..00000000000 --- a/Arrangement_on_surface_2/demo/Arrangement_on_surface_2/tests/Test.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -typedef CGAL::Exact_circular_kernel_2 CircularKernel; -typedef CGAL::Arr_circular_arc_traits_2< CircularKernel > Traits; -typedef CGAL::Arr_default_dcel< Traits > Dcel; -typedef CGAL::Arrangement_with_history_2< Traits, Dcel > Arrangement; -typedef Traits::X_monotone_curve_2 Circular_arc_2; -typedef CircularKernel::Circle_2 Circle_2; -typedef CircularKernel::Point_2 Point_2; - -typedef CGAL::Arrangement_2< Traits, Dcel > Arrangement_without_history; - -int main( ) -{ - Arrangement arr; - Arrangement_without_history arr2; - - std::ifstream ifs( "curves" ); - Traits::Curve_2 testArc, testArc2; - ifs >> testArc >> testArc2; - ifs.close( ); - - std::cout << testArc << std::endl; - std::cout << testArc2 << std::endl; - - CGAL::insert( arr, testArc ); - CGAL::insert( arr, testArc2 ); - - Point_2 p1( 0, 0 ); - Point_2 p2( 1, 0 ); - Point_2 p3( 0, 1 ); - Circle_2 circle( p1, p2, p3 ); - Circular_arc_2 arc( circle ); - Traits::Curve_2 curveBox = arc; - - std::vector< Circular_arc_2 > arcs; - arcs.push_back( arc ); - CGAL::insert( arr2, arcs.begin( ), arcs.end( ) ); - - return 0; -} diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrangementXMonotoneTraits_2.h b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrangementXMonotoneTraits_2.h index e796bbc3b0b..6d6d59c544b 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrangementXMonotoneTraits_2.h +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Concepts/ArrangementXMonotoneTraits_2.h @@ -79,7 +79,7 @@ typedef unspecified_type Split_2; /// \name /// \attention The two following function-object types are /// optional. If they are supported, the `Has_merge_category` tag -/// should be defined as `Tag_true` (and `Tag_false` otherwise. +/// should be defined as `Tag_true` and otherwise as `Tag_false`. /// @{ /*! @@ -114,8 +114,8 @@ Split_2 split_2_object() const; /// \name /// The two following methods are optional. If they are supported, the -/// `Has_merge_category` tag should be defined as `Tag_true` (and -/// `Tag_false` otherwise. +/// `Has_merge_category` tag should be defined as `Tag_true` and otherwise +/// as `Tag_false`. /// @{ /*! diff --git a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt index 86ff8829a38..226e1c6fab2 100644 --- a/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/examples/Arrangement_on_surface_2/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Arrangement_on_surface_2_Examples ) +project(Arrangement_on_surface_2_Examples) +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core) - -if ( CGAL_FOUND ) - - include(${CGAL_USE_FILE}) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include(${CGAL_USE_FILE}) +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h index 16befc318ee..16a15d7ea56 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h @@ -91,6 +91,11 @@ public: /*! Destructor. */ virtual ~Arr_vertex_base() {} + // Access/modification for pointer squatting + void* inc() const { return p_inc; } + void set_inc(void * inc) const + { const_cast(*this).p_inc = inc; } + /*! Check if the point pointer is nullptr. */ bool has_null_point() const { return (p_pt == nullptr); } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h index e4c739c8c23..393958f3424 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_overlay_2.h @@ -40,6 +40,89 @@ namespace CGAL { +template +class Indexed_sweep_accessor +{ + const Arr1& arr1; + const Arr2& arr2; + mutable std::vector backup_inc; + +public: + + Indexed_sweep_accessor (const Arr1& arr1, const Arr2& arr2) + : arr1(arr1), arr2(arr2) { } + + std::size_t nb_vertices() const + { + return arr1.number_of_vertices() + arr2.number_of_vertices(); + } + + std::size_t min_end_index (const Curve& c) const + { + if (c.red_halfedge_handle() != typename Curve::HH_red()) + return reinterpret_cast(c.red_halfedge_handle()->target()->inc()); + // else + CGAL_assertion (c.blue_halfedge_handle() != typename Curve::HH_blue()); + return reinterpret_cast(c.blue_halfedge_handle()->target()->inc()); + } + + std::size_t max_end_index (const Curve& c) const + { + if (c.red_halfedge_handle() != typename Curve::HH_red()) + return reinterpret_cast(c.red_halfedge_handle()->source()->inc()); + // else + CGAL_assertion (c.blue_halfedge_handle() != typename Curve::HH_blue()); + return reinterpret_cast(c.blue_halfedge_handle()->source()->inc()); + } + + const Curve& curve (const Curve& c) const + { + return c; + } + + // Initializes indices by squatting Vertex::inc(); + void before_init() const + { + std::size_t idx = 0; + backup_inc.resize (nb_vertices()); + for (typename Arr1::Vertex_const_iterator vit = arr1.vertices_begin(); + vit != arr1.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + backup_inc[idx] = vit->inc(); + vit->set_inc (reinterpret_cast(idx)); + } + for (typename Arr2::Vertex_const_iterator vit = arr2.vertices_begin(); + vit != arr2.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + backup_inc[idx] = vit->inc(); + vit->set_inc (reinterpret_cast(idx)); + } + } + + // Restores state of arrangements before index squatting + void after_init() const + { + std::size_t idx = 0; + for (typename Arr1::Vertex_const_iterator vit = arr1.vertices_begin(); + vit != arr1.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + vit->set_inc (backup_inc[idx]); + } + for (typename Arr2::Vertex_const_iterator vit = arr2.vertices_begin(); + vit != arr2.vertices_end(); ++vit, ++idx) + { + CGAL_assertion (idx < backup_inc.size()); + vit->set_inc (backup_inc[idx]); + } + } + +private: + +}; + /*! Compute the overlay of two input arrangements. * \tparam GeometryTraitsA_2 the geometry traits of the first arrangement. * \tparam GeometryTraitsB_2 the geometry traits of the second arrangement. @@ -183,7 +266,14 @@ overlay(const Arrangement_on_surface_2& arr1 if (total_iso_verts == 0) { // Clear the result arrangement and perform the sweep to construct it. arr.clear(); - surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end()); + if (std::is_same::value) + surface_sweep.sweep (xcvs_vec.begin(), xcvs_vec.end()); + else + surface_sweep.indexed_sweep (xcvs_vec, + Indexed_sweep_accessor + + (arr1, arr2)); xcvs_vec.clear(); return; } @@ -215,8 +305,16 @@ overlay(const Arrangement_on_surface_2& arr1 // Clear the result arrangement and perform the sweep to construct it. arr.clear(); - surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end(), - pts_vec.begin(), pts_vec.end()); + if (std::is_same::value) + surface_sweep.sweep(xcvs_vec.begin(), xcvs_vec.end(), + pts_vec.begin(), pts_vec.end()); + else + surface_sweep.indexed_sweep (xcvs_vec, + Indexed_sweep_accessor + + (arr1, arr2), + pts_vec.begin(), pts_vec.end()); xcvs_vec.clear(); pts_vec.clear(); } diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_traits_2.h index 7e732f09a65..6e26162ea0a 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_polycurve_traits_2.h @@ -716,14 +716,19 @@ public: Comparison_result dir1 = cmp_seg_endpts(cv1[0]); Comparison_result dir2 = cmp_seg_endpts(cv2[0]); + std::vector ocv; // Used to represent overlaps. + const bool invert_ocv = ((dir1 == LARGER) && (dir2 == LARGER)); + const bool consistent = (dir1 == dir2); +#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT + CGAL_assertion(consistent); +#endif + const std::size_t n1 = cv1.number_of_subcurves(); const std::size_t n2 = cv2.number_of_subcurves(); std::size_t i1 = (dir1 == SMALLER) ? 0 : n1-1; std::size_t i2 = (dir2 == SMALLER) ? 0 : n2-1; - X_monotone_curve_2 ocv; // Used to represent overlaps. - auto compare_xy = m_poly_traits.compare_xy_2_object(); Comparison_result left_res = compare_xy(cv1[i1], ARR_MIN_END, cv2[i2], ARR_MIN_END); @@ -825,8 +830,7 @@ public: boost::get(&xection); if (subcv_p != nullptr) { ocv.push_back(*subcv_p); - *oi++ = Intersection_result(ocv); - ocv.clear(); + oi = output_ocv (ocv, invert_ocv, oi); continue; } @@ -848,10 +852,16 @@ public: boost::get(&item); if (x_seg != nullptr) { X_monotone_subcurve_2 seg = *x_seg; - - // If for some reason the subcurve intersection - // results in left oriented curve. - if (cmp_seg_endpts(seg) == LARGER) seg = construct_opposite(seg); + // We maintain the variant that if the input curves have opposite + // directions (! consistent), the overalpping curves are directed + // left=>right. This, however, is not guaranteed for the + // subcurves. Therefore, we need to enforce it. That is, we make + // sure the subcurves are also directed left=>right in this case. + if (! consistent && (cmp_seg_endpts(seg) == LARGER)) + seg = construct_opposite(seg); +#ifdef CGAL_ALWAYS_LEFT_TO_RIGHT + CGAL_assertion(cmp_seg_endpts(seg) == SMALLER); +#endif ocv.push_back(seg); } @@ -876,9 +886,8 @@ public: if (left_overlap) { // An overlap occurred at the previous iteration: // Output the overlapping polycurve. - CGAL_assertion(ocv.number_of_subcurves() > 0); - *oi++ = Intersection_result(ocv); - ocv.clear(); + CGAL_assertion(ocv.size() > 0); + oi = output_ocv (ocv, invert_ocv, oi); } else { // The left point of the current subcurve of one @@ -923,8 +932,8 @@ public: } // END of while loop // Output the remaining overlapping polycurve, if necessary. - if (ocv.number_of_subcurves() > 0) { - *oi++ = Intersection_result(ocv); + if (ocv.size() > 0) { + oi = output_ocv (ocv, invert_ocv, oi); } else if (right_coincides) { typedef std::pair return_point; @@ -974,6 +983,27 @@ public: } } + return oi; + } + + private: + + template + inline OutputIterator output_ocv + (std::vector& ocv, bool invert_ocv, OutputIterator oi) const + { + typedef std::pair Intersection_point; + typedef boost::variant + Intersection_result; + X_monotone_curve_2 curve; + if (invert_ocv) + std::reverse (ocv.begin(), ocv.end()); + for (X_monotone_subcurve_2& sc : ocv) + curve.push_back (sc); + *(oi ++) = Intersection_result(curve); + + ocv.clear(); + return oi; } }; diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h index 575f797d293..6ce3ad5edbf 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_segment_traits_2.h @@ -82,12 +82,13 @@ public: typedef typename Kernel::Point_2 Point_2; protected: - Line_2 m_l; // the line that supports the segment. - Point_2 m_ps; // the source point of the segment. - Point_2 m_pt; // the target point of the segment. - bool m_is_directed_right; // is (lexicographically) directed left to right. - bool m_is_vert; // is this a vertical segment. - bool m_is_degen; // is the segment degenerate (a single point). + mutable Line_2 m_l; // the line that supports the segment. + Point_2 m_ps; // the source point of the segment. + Point_2 m_pt; // the target point of the segment. + bool m_is_directed_right; // is (lexicographically) directed left to right. + mutable bool m_is_vert; // is this a vertical segment. + mutable bool m_is_computed; // is the support line computed. + bool m_is_degen; // is the segment degenerate (a single point). public: @@ -1170,13 +1171,16 @@ template Arr_segment_traits_2::_Segment_cached_2::_Segment_cached_2() : m_is_directed_right(false), m_is_vert(false), + m_is_computed(false), m_is_degen(true) {} //! \brief constructs a segment from a Kernel segment. template Arr_segment_traits_2:: -_Segment_cached_2::_Segment_cached_2(const Segment_2& seg) +_Segment_cached_2::_Segment_cached_2(const Segment_2& seg) : + m_is_vert(false), + m_is_computed(false) { Kernel kernel; auto vertex_ctr = kernel.construct_vertex_2_object(); @@ -1189,9 +1193,6 @@ _Segment_cached_2::_Segment_cached_2(const Segment_2& seg) m_is_directed_right = (res == SMALLER); CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); - - m_l = kernel.construct_line_2_object()(seg); - m_is_vert = kernel.is_vertical_2_object()(seg); } //! \brief Constructs a segment from two endpoints. @@ -1200,7 +1201,9 @@ Arr_segment_traits_2:: _Segment_cached_2::_Segment_cached_2(const Point_2& source, const Point_2& target) : m_ps(source), - m_pt(target) + m_pt(target), + m_is_vert(false), + m_is_computed(false) { Kernel kernel; @@ -1209,9 +1212,6 @@ _Segment_cached_2::_Segment_cached_2(const Point_2& source, m_is_directed_right = (res == SMALLER); CGAL_precondition_msg(! m_is_degen, "Cannot construct a degenerate segment."); - - m_l = kernel.construct_line_2_object()(source, target); - m_is_vert = kernel.is_vertical_2_object()(m_l); } //! \brief constructs a segment from two endpoints on a supporting line. @@ -1233,6 +1233,7 @@ _Segment_cached_2::_Segment_cached_2(const Line_2& line, Has_exact_division())); m_is_vert = kernel.is_vertical_2_object()(m_l); + m_is_computed = true; Comparison_result res = kernel.compare_xy_2_object()(m_ps, m_pt); m_is_degen = (res == EQUAL); @@ -1252,6 +1253,7 @@ _Segment_cached_2(const Line_2& line, m_pt(target), m_is_directed_right(is_directed_right), m_is_vert(is_vert), + m_is_computed(true), m_is_degen(is_degen) {} @@ -1274,6 +1276,7 @@ Arr_segment_traits_2::_Segment_cached_2::operator=(const Segment_2& seg) m_l = kernel.construct_line_2_object()(seg); m_is_vert = kernel.is_vertical_2_object()(seg); + m_is_computed = true; return (*this); } @@ -1283,12 +1286,26 @@ Arr_segment_traits_2::_Segment_cached_2::operator=(const Segment_2& seg) //! \brief obtains the supporting line. template const typename Kernel::Line_2& -Arr_segment_traits_2::_Segment_cached_2::line() const { return m_l; } +Arr_segment_traits_2::_Segment_cached_2::line() const +{ + if (!m_is_computed) { + Kernel kernel; + m_l = kernel.construct_line_2_object()(m_ps, m_pt); + m_is_vert = kernel.is_vertical_2_object()(m_l); + m_is_computed = true; + } + return m_l; +} //! \brief determines whether the curve is vertical. template bool Arr_segment_traits_2::_Segment_cached_2::is_vertical() const -{ return m_is_vert; } +{ + // Force computation of line is orientation is still unknown + if (! m_is_computed) line(); + CGAL_precondition(!m_is_degen); + return m_is_vert; +} //! \brief determines whether the curve is degenerate. template @@ -1447,12 +1464,7 @@ public: /*! Create a bounding box for the segment. */ - Bbox_2 bbox() const - { - Kernel kernel; - auto construct_bbox = kernel.construct_bbox_2_object(); - return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); - } + Bbox_2 bbox() const; }; //! \brief constructs default. @@ -1506,6 +1518,15 @@ Arr_segment_2 Arr_segment_2::flip() const this->is_degenerate()); } +//! \brief creates a bounding box for the segment. +template +Bbox_2 Arr_segment_2::bbox() const +{ + Kernel kernel; + auto construct_bbox = kernel.construct_bbox_2_object(); + return construct_bbox(this->m_ps) + construct_bbox(this->m_pt); +} + /*! Exporter for the segment class used by the traits-class. */ template diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Arc_2.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Arc_2.h index f0fdab150de..ea0df939fd7 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Arc_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Arc_2.h @@ -2968,8 +2968,12 @@ private: kernel().approximate_absolute_y_2_object()( arc.curve_end(end).xy(), prec ); + break; } + default: { + CGAL_error(); + } } // switch return std::make_pair(CGAL::to_double(y_approx.first), @@ -3053,8 +3057,8 @@ public: y_dapprox = y_interval_for_curve_end(*this, CGAL::ARR_MAX_END, prec); // adapt y-interval - ymin = CGAL::min(ymin, y_dapprox.first); - ymax = CGAL::max(ymax, y_dapprox.second); + ymin = (CGAL::min)(ymin, y_dapprox.first); + ymax = (CGAL::max)(ymax, y_dapprox.second); // search local extrema on a non-vertical arc @@ -3130,9 +3134,9 @@ public: (curr_xy, prec); // adapt y-interval - ymin = CGAL::min(ymin, + ymin = (CGAL::min)(ymin, CGAL::to_double(xy_approx.first)); - ymax = CGAL::max(ymax, + ymax = (CGAL::max)(ymax, CGAL::to_double(xy_approx.second)); } } diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h index 8a26fb9ee55..d7accae1dc9 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/Point_2.h @@ -384,7 +384,7 @@ public: return *(this->ptr()->_m_xy); } - inline const Coordinate_1& y() const { + inline const Coordinate_1 y() const { return this->xy().y(); } diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_2.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_2.h index 2389d8aea7b..745381dc630 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_2.h @@ -238,7 +238,8 @@ private: typedef std::vector index_vector; //! map container element's type for maintaining a list of cache instances - typedef std::pair LRU_entry; + typedef std::pair LRU_entry; + //! LRU list used for cache switching typedef std::vector< LRU_entry > Cache_list; @@ -256,8 +257,9 @@ public: //!@{ //! default constructor: a curve segment is undefined - Curve_renderer_2() : cache_id(-1), IA_method(0), initialized(false), - one(1) { + Curve_renderer_2() : + cache_id(INVALID_CACHE_ID), IA_method(0), initialized(false), one(1) + { arcno = -1; setup(Bbox_2(-1.0, -1.0, 1.0, 1.0), 640, 480); } @@ -381,9 +383,11 @@ private: Clip_points btm_clip, top_clip; //! a set of bottom and top clip points Poly_dst_1 btm_poly, top_poly; //! bottom and top polynomials - int cache_id; //! index of currently used cache instance + std::size_t cache_id; //! index of currently used cache instance Cache_list cache_list; //! list of indices of cache instances + static constexpr std::size_t INVALID_CACHE_ID = CGAL_N_CACHES; + Seed_stack s_stack; //! a stack of seed points Seed_point current_seed; //! current seed point @@ -1192,7 +1196,7 @@ Lexit: std::reverse(rev_points.begin(), rev_points.end()); // resize rev_points to accommodate the size of points vector - unsigned rsize = rev_points.size(); + std::size_t rsize = rev_points.size(); rev_points.resize(rsize + points.size()); std::copy(points.begin(), points.end(), rev_points.begin() + rsize); } @@ -1750,7 +1754,7 @@ void segment_clip_points(const Rational& x_lower, const Rational& x_upper, // high = ubound_y(xy); //TODO: no need to refine y-intervals: you need only to check whether // polynomial vanishes at y_clip, since algebraic real you specify is exact - if((_.first < y_clip && _.second > y_clip)|| + if(( (_.first < y_clip) && (_.second > y_clip) ) || _.first == y_clip || _.second == y_clip) { //event.refine_to(i, engine.pixel_h_r/CGAL_REFINE_Y); Rational _1, _2; @@ -2312,7 +2316,8 @@ void select_cache_entry(const Arc_2& arc) { it++; } - int new_id, new_entry = (it == cache_list.end()); + std::size_t new_id; + bool new_entry = (it == cache_list.end()); if(new_entry) { new_id = cache_list.size(); if(new_id >= CGAL_N_CACHES) { @@ -2579,8 +2584,8 @@ inline bool is_isolated_pixel(const Pixel_2& /* pix */) { } // DEBUG ONLY -void dump_neighbourhood(const Pixel_2& pix) { #ifdef Gfx_USE_OUT +void dump_neighbourhood(const Pixel_2& pix) { CGAL::set_mode(std::cerr, CGAL::IO::PRETTY); CGAL::set_mode(std::cout, CGAL::IO::PRETTY); @@ -2757,8 +2762,10 @@ void dump_neighbourhood(const Pixel_2& pix) { Gfx_OUT("val = " << b << std::endl); if(a*b < 0) Gfx_OUT("sign change at segment 2" << std::endl); -#endif // Gfx_USE_OUT } +#else +void dump_neighbourhood(const Pixel_2&) { } +#endif // Gfx_USE_OUT //!@} }; // class Curve_renderer_2<> diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_internals.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_internals.h index 1c0ca9cf40b..984ea6170a6 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_internals.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_internals.h @@ -88,21 +88,12 @@ struct Pixel_2_ Integer sub_x, sub_y; // subpixel coordinates relative to pixel's boundary // (always 0 for pixels) - Pixel_2_& operator =(const Pixel_2_& pix) { -#ifdef CGAL_CKVA_RENDER_WITH_REFINEMENT - memcpy(this, &pix, sizeof(int)*3 + sizeof(double)*2); -#else - memcpy(this, &pix, sizeof(int)*3); -#endif - sub_x = pix.sub_x; - sub_y = pix.sub_y; - return *this; - } + Pixel_2_& operator =(const Pixel_2_& pix) = default; bool operator ==(const Pixel_2_& pix) const { - if(memcmp(this, &pix, sizeof(int)*3)) - return false; - return (sub_x == pix.sub_x && sub_y == pix.sub_y); + return ( + x == pix.x && y == pix.y && level == pix.level && + sub_x == pix.sub_x && sub_y == pix.sub_y); } }; @@ -297,7 +288,8 @@ public: const_iterator_1 poly_it = poly.end() - 1; der_iterator_1 der_it = der_coeffs.end() - 1; NT y(extract(*poly_it--) * (*der_it)); - while((der_it--) != der_coeffs.begin()) { + while(der_it != der_coeffs.begin()) { + --der_it; y = y * x + extract(*poly_it--) * (*der_it); } return y; @@ -351,8 +343,10 @@ public: Rat_coercion_type r = rit->evaluate(x), yc = typename Coercion::Cast()(y); - while((rit--) != poly.begin()) + while(rit != poly.begin()) { + --rit; r = r * yc + rit->evaluate(x); + } return r; } @@ -555,7 +549,8 @@ bool get_range_AF1_1(int var, make_exact(x1); NT x0_abs = CGAL_ABS(x0), x1_abs = CGAL_ABS(x1); - while((der_it_2--) != der->begin()) { + while(der_it_2 != der->begin()) { + --der_it_2; // iterate through derivative coefficients der_it = der_it_2->end() - 1; der_begin = der_it_2->begin(); @@ -565,7 +560,9 @@ bool get_range_AF1_1(int var, if(low * up >= 0) { v1 = v2 = extract(*cache_it--) * (*der_it); // calculate the ith derivative at xa and xb - while((der_it--) != der_begin) { + while(der_it != der_begin) { + --der_it; + NT cc1 = extract(*cache_it--) * (*der_it); v1 = v1 * l1 + cc1; v2 = v2 * r1 + cc1; @@ -575,7 +572,9 @@ bool get_range_AF1_1(int var, NT y0 = extract(*cache_it) * (*der_it), y1(0), e1(0); cache_it--; - while((der_it--)!=der_begin) { + while(der_it!=der_begin) { + --der_it; + e1 = x0_abs*e1 + x1_abs*(CGAL_ABS(y1) + CGAL_ABS(e1)); y1 = y1*x0 + x1*y0; y0 = x0*y0 + extract(*cache_it) * (*der_it); @@ -596,7 +595,8 @@ bool get_range_AF1_1(int var, begin = poly.begin(); NT y0 = extract(*cache_it), y1(0), e1(0); - while((cache_it--) != begin) { + while(cache_it != begin) { + --cache_it; e1 = x0_abs*e1 + x1_abs*(CGAL_ABS(y1) + CGAL_ABS(e1)); y1 = y1*x0 + x1*y0; y0 = x0*y0 + extract(*cache_it); @@ -673,8 +673,8 @@ bool get_range_QF_1(int var, const NT& l_, const NT& r_, const NT& key, make_exact(x1); NT x0_abs = CGAL_ABS(x0), xsum_abs = CGAL_ABS(x1) + x0_abs; - while((der_it_2--)!=der->begin()) { - + while(der_it_2!=der->begin()) { + --der_it_2; // iterate through derivative coefficients der_it = (*der_it_2).end()-1; der_begin = (*der_it_2).begin(); @@ -685,7 +685,9 @@ bool get_range_QF_1(int var, const NT& l_, const NT& r_, const NT& key, if(low * up >= 0) { v1 = v2 = extract(*cache_it--)* (*der_it); // calculate the ith derivative at xa and xb - while((der_it--) != der_begin) { + while(der_it != der_begin) { + --der_it; + NT cc1 = extract(*cache_it--)* (*der_it); v1 = v1 * l1 + cc1; v2 = v2 * r1 + cc1; @@ -696,7 +698,9 @@ bool get_range_QF_1(int var, const NT& l_, const NT& r_, const NT& key, NT y0 = extract(*cache_it) * (*der_it), y1(0), z1(0), e1(0); cache_it--; - while((der_it--)!=der_begin) { + while(der_it != der_begin) { + --der_it; + e1 = xsum_abs * e1 + CGAL_ABS(x1 * z1); z1 = x0*z1 + x1*y1; y1 = y1*x0 + x1*y0; @@ -726,7 +730,8 @@ bool get_range_QF_1(int var, const NT& l_, const NT& r_, const NT& key, cache_it = poly.end()-1; begin = poly.begin(); NT y0 = extract(*cache_it), y1(0), z1(0), e1(0); - while((cache_it--) != begin) { + while(cache_it != begin) { + --cache_it; e1 = xsum_abs * e1 + CGAL_ABS(x1*z1); z1 = x0*z1 + x1*y1; y1 = y1*x0 + x1*y0; @@ -861,8 +866,9 @@ bool get_range_MAA_1(int var, const NT& l_, const NT& r_, const NT& key, eval1 = CGAL_SGN(low); eval2 = CGAL_SGN(up); - } else if(d == 0) + } else if(d == 0) { ;//Gfx_DETAILED_OUT("MAA bounds: sign change\n"); + } if(d == 1 && check == 3) { first_der = (eval1*eval2 < 0); @@ -874,8 +880,9 @@ bool get_range_MAA_1(int var, const NT& l_, const NT& r_, const NT& key, return (eval1*eval2 < 0); } d--; der_it_2--; - if((eval_it--) == der_cache.begin()) + if(eval_it == der_cache.begin()) break; + eval_it--; } return true; } @@ -928,13 +935,11 @@ void get_precached_poly(int var, const NT& key, int /* level */, Poly_1& poly) //! recomputed with modular or exact rational arithmetic int evaluate_generic(int var, const NT& c, const NT& key, const Poly_1& poly) { - NT x = key, y = c, c1; + NT c1; - if(var == CGAL_X_RANGE) { - x = c; - y = key; + if(var == CGAL_X_RANGE) c1 = x_min + c*pixel_w; - } else + else c1 = y_min + c*pixel_h; bool error_bounds_; @@ -977,7 +982,7 @@ void precompute(const Polynomial_2& in) { Coeff_src max_c = max_coeff(in); /////// magic symbol //////////// // somehow relates to double precision fix - std::cerr << ' '; + // std::cerr << ' '; typedef Reduce_by Reduce_op; Transform transform; @@ -1038,7 +1043,7 @@ void precompute(const Polynomial_2& in) { } //! \brief activates the cache entry \c cache_id -void select_cache_entry(int cache_id) +void select_cache_entry(std::size_t cache_id) { coeffs_x = coeffs_x_ + cache_id; coeffs_y = coeffs_y_ + cache_id; diff --git a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_traits.h b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_traits.h index bf85bc0a54c..752389a0f35 100644 --- a/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_traits.h +++ b/Arrangement_on_surface_2/include/CGAL/Curved_kernel_via_analysis_2/gfx/Curve_renderer_traits.h @@ -55,13 +55,13 @@ struct Max_coeff { typename CGAL::Polynomial::const_iterator it = p.begin(); Max_coeff max_coeff; - NT max(max_coeff(*it)); + NT cur_max(max_coeff(*it)); while(++it != p.end()) { NT tmp(max_coeff(*it)); - if(max < CGAL_ABS(tmp)) - max = CGAL_ABS(tmp); + if(cur_max < CGAL_ABS(tmp)) + cur_max = CGAL_ABS(tmp); } - return max; + return cur_max; } NT operator()(const NT& x) const { return CGAL_ABS(x); } @@ -241,7 +241,7 @@ struct Curve_renderer_traits_base typedef void result_type; template - void operator()(const Float& x) const + void operator()(const Float& /*x*/) const { } }; @@ -251,7 +251,7 @@ struct Curve_renderer_traits_base typedef bool result_type; template - bool operator()(const Float& x) const + bool operator()(const Float& /*x*/) const { return false;/*(CGAL_ABS(x) <= 1e-16)*/; } }; diff --git a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h index 48815d767f6..3243890c1be 100644 --- a/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Surface_sweep_2/Arr_overlay_traits_2.h @@ -133,6 +133,8 @@ public: class Ex_x_monotone_curve_2 { public: typedef Base_x_monotone_curve_2 Base; + typedef Halfedge_handle_red HH_red; + typedef Halfedge_handle_blue HH_blue; protected: Base m_base_xcv; // The base curve. diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/CMakeLists.txt b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/CMakeLists.txt index 0ffdc893571..bc3f1b89e7a 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/CMakeLists.txt +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/CMakeLists.txt @@ -1,35 +1,28 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Arrangement_on_surface_2_Tests ) +project(Arrangement_on_surface_2_Tests) enable_testing() +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core) - -if ( CGAL_FOUND ) - - include(${CGAL_USE_FILE}) - - if(COMMAND target_compile_options) - # Since CMake-2.8.12: New CMake script, that defines the targets and - # the CTest test cases. - include( ${CMAKE_CURRENT_SOURCE_DIR}/cgal_test.cmake ) - else() - # If CMake version is <= 2.8.11, use the usual CMake script. - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - endif() +include(${CGAL_USE_FILE}) +if(COMMAND target_compile_options) + # Since CMake-2.8.12: New CMake script, that defines the targets and + # the CTest test cases. + include(${CMAKE_CURRENT_SOURCE_DIR}/cgal_test.cmake) else() + # If CMake version is <= 2.8.11, use the usual CMake script. - message(STATUS "This program requires the CGAL library, and will not be compiled.") - + # create a target per cppfile + file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") + endforeach() endif() diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake index 7fd18c6944b..d6ae0f045bb 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test.cmake @@ -911,7 +911,7 @@ function(test_polycurve_conic_traits) compile_test_with_flags(test_traits conic_polycurve "${flags}") # The input arguments for the execute_commands_new_structure, - # 1. Polycurve_conics is the directory name in "data" + # 1. polycurve_conics is the directory name in "data" # 2. polycurve_conic_traits is a string # Execute_command_new_structure will only run the test on functors provided as the third, fourth and so on arguments. # To see how the input data directory should be structured for each functor, check the execute_commands_new_structure function in this file. @@ -947,7 +947,7 @@ function(test_polycurve_circular_arc_traits) compile_test_with_flags(test_traits circular_arc_polycurve "${flags}") - execute_commands_new_structure(Polycurves_circular_arcs polycurve_circular_arc_traits + execute_commands_new_structure(polycurves_circular_arcs polycurve_circular_arc_traits COMPARE_Y_AT_X EQUAL IS_VERTICAL @@ -981,7 +981,7 @@ function(test_polycurve_bezier_traits) compile_test_with_flags(test_traits bezier_polycurve "${flags}") - execute_commands_new_structure(Polycurves_bezier test_polycurve_bezier_traits + execute_commands_new_structure(polycurves_bezier test_polycurve_bezier_traits MERGE EQUAL IS_VERTICAL @@ -1422,3 +1422,5 @@ compile_and_run(test_spherical_removal) compile_and_run(test_io) compile_and_run(test_sgm) + +compile_and_run(test_polycurve_intersection) diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake index 78c93619658..c1183a846d8 100755 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/cgal_test_with_cmake @@ -1127,7 +1127,7 @@ test_polycurve_conic_traits() if [ -n "${SUCCESS}" ] ; then # The input arguments for the execute_commands_new_structure, - # 1. Polycurve_conics is the directory name in "data" + # 1. polycurve_conics is the directory name in "data" # 2. polycurve_conic_traits is a string # Execute_command_new_structure will only run the test on functors provided as the third, fourth and so on arguments. # To see how the input data directory should be structured for each functor, check the execute_commands_new_structure function in this file. @@ -1168,7 +1168,7 @@ test_polycurve_circular_arc_traits() compile_test_with_flags test_traits circular_arc_polycurve "$flags" if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure Polycurves_circular_arcs polycurve_circular_arc_traits \ + execute_commands_new_structure polycurves_circular_arcs polycurve_circular_arc_traits \ COMPARE_Y_AT_X \ EQUAL \ IS_VERTICAL \ @@ -1208,7 +1208,7 @@ test_polycurve_bezier_traits() compile_test_with_flags test_traits bezier_polycurve "$flags" if [ -n "${SUCCESS}" ] ; then - execute_commands_new_structure Polycurves_bezier test_polycurve_bezier_traits \ + execute_commands_new_structure polycurves_bezier test_polycurve_bezier_traits \ MERGE \ EQUAL \ IS_VERTICAL \ @@ -1751,6 +1751,8 @@ compile_and_run test_io compile_and_run test_sgm +compile_and_run test_polycurve_intersection + # if any error occurred then append the full error description file to error file if [ -f $FULL_ERROR_DESCRIPTION_FILE ] ; then diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/are_mergeable b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/are_mergeable similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/are_mergeable rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/are_mergeable diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_endpoints_xy b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_endpoints_xy similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_endpoints_xy rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_endpoints_xy diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_x b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_x similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_x rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_x diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_xy b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_xy similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_xy rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_xy diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x_left b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x_left similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x_left rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x_left diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x_right b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x_right similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/compare_y_at_x_right rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/compare_y_at_x_right diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/construct_opposite b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/construct_opposite similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/construct_opposite rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/construct_opposite diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/curves b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/curves similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/curves rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/curves diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/equal b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/equal similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/equal rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/equal diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/intersect b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/intersect similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/intersect rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/intersect diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/is_vertical b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/is_vertical similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/is_vertical rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/is_vertical diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/make_x_monotone b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/make_x_monotone similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/make_x_monotone rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/make_x_monotone diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/merge b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/merge similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/merge rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/merge diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/number_of_points b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/number_of_points similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/number_of_points rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/number_of_points diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/points b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/points similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/points rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/points diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/push_back b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/push_back similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/push_back rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/push_back diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/push_front b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/push_front similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/push_front rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/push_front diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/split b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/split similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/split rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/split diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/trim b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/trim similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/trim rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/trim diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/vertex b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/vertex similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/vertex rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/vertex diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/xcurves b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/xcurves similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_bezier/xcurves rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_bezier/xcurves diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/are_mergeable b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/are_mergeable similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/are_mergeable rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/are_mergeable diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_endpoints_xy b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_endpoints_xy similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_endpoints_xy rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_endpoints_xy diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_x b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_x similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_x rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_x diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_xy b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_xy similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_xy rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_xy diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x_left b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x_left similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x_left rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x_left diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x_right b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x_right similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/compare_y_at_x_right rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/compare_y_at_x_right diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/construct_opposite b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/construct_opposite similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/construct_opposite rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/construct_opposite diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/curves b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/curves similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/curves rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/curves diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/equal b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/equal similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/equal rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/equal diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/intersect b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/intersect similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/intersect rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/intersect diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/is_vertical b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/is_vertical similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/is_vertical rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/is_vertical diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/make_x_monotone b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/make_x_monotone similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/make_x_monotone rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/make_x_monotone diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/merge b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/merge similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/merge rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/merge diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/number_of_points b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/number_of_points similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/number_of_points rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/number_of_points diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/points b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/points similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/points rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/points diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/push_back b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/push_back similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/push_back rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/push_back diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/push_front b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/push_front similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/push_front rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/push_front diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/split b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/split similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/split rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/split diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/trim b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/trim similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/trim rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/trim diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/vertex b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/vertex similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/vertex rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/vertex diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/xcurves b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/xcurves similarity index 100% rename from Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/Polycurves_circular_arcs/xcurves rename to Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/polycurves_circular_arcs/xcurves diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_polycurve_intersection.cpp b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_polycurve_intersection.cpp new file mode 100644 index 00000000000..5cfd7a64f2e --- /dev/null +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_polycurve_intersection.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include + +#include + +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Arr_segment_traits_2 Segment_traits_2; +typedef CGAL::Arr_polyline_traits_2 Geom_traits_2; + +typedef Geom_traits_2::Point_2 Point_2; +typedef Geom_traits_2::Segment_2 Segment_2; +typedef Geom_traits_2::Curve_2 Polyline_2; +typedef CGAL::Arrangement_2 Arrangement_2; +typedef Geom_traits_2::X_monotone_curve_2 X_monotone_polyline; +typedef Geom_traits_2::X_monotone_subcurve_2 X_monotone_subcurve; + +struct Test_functor +{ + const X_monotone_polyline* reference; + + Test_functor (const X_monotone_polyline& reference) + : reference (&reference) { } + + void operator() (const CGAL::Object& obj) const + { + const X_monotone_polyline* poly + = CGAL::object_cast(&obj); + CGAL_assertion_msg (poly != nullptr, "Intersection is not a polyline"); + + typename X_monotone_polyline::Point_const_iterator + itref = reference->points_begin(), + itpoly = poly->points_begin(); + + for (; itref != reference->points_end() + && itpoly != poly->points_end(); + ++ itref, ++ itpoly) + CGAL_assertion (*itref == *itpoly); + } +}; + +void test (const X_monotone_polyline& a, const X_monotone_polyline& b, + const X_monotone_polyline& reference) +{ + Geom_traits_2 traits; + Geom_traits_2::Intersect_2 intersect_2 = + traits.intersect_2_object(); + + std::cerr << " * Polyline A = " << a << std::endl + << " * Polyline B = " << b << std::endl; + + intersect_2 + (a, b, boost::make_function_output_iterator (Test_functor(reference))); +} + +int main() +{ + Geom_traits_2 traits; + Arrangement_2 arr(&traits); + + Geom_traits_2::Construct_x_monotone_curve_2 x_mono_polyline_construct = + traits.construct_x_monotone_curve_2_object(); + + std::array r2l + = { Segment_2(Point_2(1, 0), Point_2(0, 1)), + Segment_2(Point_2(0, 1), Point_2(-1, 0)) }; + + std::array l2r + = { Segment_2(Point_2(-1, 0), Point_2(0, 1)), + Segment_2(Point_2(0, 1), Point_2(1, 0)), }; + + X_monotone_polyline p0l2r + = x_mono_polyline_construct (l2r.begin(), l2r.end()); + X_monotone_polyline p1l2r + = x_mono_polyline_construct (l2r.begin(), l2r.end()); + X_monotone_polyline p0r2l + = x_mono_polyline_construct (r2l.begin(), r2l.end()); + X_monotone_polyline p1r2l + = x_mono_polyline_construct (r2l.begin(), r2l.end()); + + std::cerr << "Testing intersection left-to-right / left-to-right" << std::endl; + test (p0l2r, p1l2r, p0l2r); + std::cerr << "Testing intersection left-to-right / right-to-left" << std::endl; + test (p0l2r, p1r2l, p0l2r); + std::cerr << "Testing intersection right-to-left / left-to-right" << std::endl; + test (p0r2l, p1l2r, p0l2r); + std::cerr << "Testing intersection right-to-left / right-to-left" << std::endl; + test (p0r2l, p1r2l, p0r2l); + + return EXIT_SUCCESS; +} diff --git a/BGL/doc/BGL/Concepts/FaceGraph.h b/BGL/doc/BGL/Concepts/FaceGraph.h index 08501700261..40346595ac6 100644 --- a/BGL/doc/BGL/Concepts/FaceGraph.h +++ b/BGL/doc/BGL/Concepts/FaceGraph.h @@ -25,7 +25,7 @@ A face descriptor must be `DefaultConstructible`, `Assignable`, `EqualityCompara \sa \link PkgBGLConcepts Graph Concepts \endlink */ class FaceGraph { - /// Returns a special `boost::graph_traits::face_descriptor` object which + /// Returns a special `boost::graph_traits::%face_descriptor` object which /// does not refer to any face of graph object which type is `FaceGraph`. static boost::graph_traits::halfedge_descriptor null_face(); }; diff --git a/BGL/doc/BGL/Concepts/HalfedgeGraph.h b/BGL/doc/BGL/Concepts/HalfedgeGraph.h index b69cbb20447..3769db82e16 100644 --- a/BGL/doc/BGL/Concepts/HalfedgeGraph.h +++ b/BGL/doc/BGL/Concepts/HalfedgeGraph.h @@ -44,7 +44,7 @@ A model of `HalfedgeGraph` must have the interior property `vertex_point` attach \sa \link PkgBGLConcepts Graph Concepts \endlink */ class HalfedgeGraph { - /// Returns a special `boost::graph_traits::halfedge_descriptor` object which + /// Returns a special `boost::graph_traits::%halfedge_descriptor` object which /// does not refer to any halfedge of graph object which type is `HalfedgeGraph`. static boost::graph_traits::halfedge_descriptor null_halfedge(); }; diff --git a/BGL/examples/BGL_LCC/CMakeLists.txt b/BGL/examples/BGL_LCC/CMakeLists.txt index fea37899fae..0c2bc149e12 100644 --- a/BGL/examples/BGL_LCC/CMakeLists.txt +++ b/BGL/examples/BGL_LCC/CMakeLists.txt @@ -2,26 +2,18 @@ # This is the CMake script for compiling a set of CGAL applications. cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_LCC_Examples ) - - +project(BGL_LCC_Examples) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() +find_package(CGAL REQUIRED) # Boost and its components -find_package( Boost REQUIRED ) +find_package(Boost REQUIRED) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() @@ -33,7 +25,10 @@ endif() # ########################################################## # create a target per cppfile -file(GLOB_RECURSE cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) +file( + GLOB_RECURSE cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + *.cpp) foreach(cppfile ${cppfiles}) create_single_source_cgal_program("${cppfile}") endforeach() diff --git a/BGL/examples/BGL_OpenMesh/CMakeLists.txt b/BGL/examples/BGL_OpenMesh/CMakeLists.txt index 685f9bc7367..e23d15c960a 100644 --- a/BGL/examples/BGL_OpenMesh/CMakeLists.txt +++ b/BGL/examples/BGL_OpenMesh/CMakeLists.txt @@ -2,38 +2,31 @@ # This is the CMake script for compiling a set of CGAL applications. cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_OpenMesh_Examples ) - - +project(BGL_OpenMesh_Examples) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() +find_package(CGAL REQUIRED) # Boost and its components -find_package( Boost REQUIRED ) +find_package(Boost REQUIRED) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() endif() -find_package( OpenMesh QUIET ) +find_package(OpenMesh QUIET) -if ( OpenMesh_FOUND ) -include( UseOpenMesh ) +if(OpenMesh_FOUND) + include(UseOpenMesh) else() - message(STATUS "NOTICE: These examples require OpenMesh and will not be compiled.") + message( + STATUS "NOTICE: These examples require OpenMesh and will not be compiled.") return() endif() @@ -46,7 +39,6 @@ endif() # ########################################################## if(OpenMesh_FOUND) - create_single_source_cgal_program( "TriMesh.cpp" ) - target_link_libraries( TriMesh PRIVATE ${OPENMESH_LIBRARIES} ) + create_single_source_cgal_program("TriMesh.cpp") + target_link_libraries(TriMesh PRIVATE ${OPENMESH_LIBRARIES}) endif() - diff --git a/BGL/examples/BGL_arrangement_2/CMakeLists.txt b/BGL/examples/BGL_arrangement_2/CMakeLists.txt index 31b9e348019..b4a1dcb0228 100644 --- a/BGL/examples/BGL_arrangement_2/CMakeLists.txt +++ b/BGL/examples/BGL_arrangement_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_arrangement_2_Examples ) +project(BGL_arrangement_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/BGL/examples/BGL_graphcut/CMakeLists.txt b/BGL/examples/BGL_graphcut/CMakeLists.txt index 56ee0be7a92..0119b961465 100644 --- a/BGL/examples/BGL_graphcut/CMakeLists.txt +++ b/BGL/examples/BGL_graphcut/CMakeLists.txt @@ -3,26 +3,18 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_graphcut_Examples ) - +project(BGL_graphcut_Examples) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() - +find_package(CGAL REQUIRED) # Boost and its components -find_package( Boost REQUIRED ) +find_package(Boost REQUIRED) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() @@ -32,12 +24,9 @@ endif() # include for local package - # Creating entries for all C++ files with "main" routine # ########################################################## - -create_single_source_cgal_program( "alpha_expansion_example.cpp" ) -create_single_source_cgal_program( "face_selection_borders_regularization_example.cpp" ) - - +create_single_source_cgal_program("alpha_expansion_example.cpp") +create_single_source_cgal_program( + "face_selection_borders_regularization_example.cpp") diff --git a/BGL/examples/BGL_polyhedron_3/CMakeLists.txt b/BGL/examples/BGL_polyhedron_3/CMakeLists.txt index 61216b99fdf..82daa190332 100644 --- a/BGL/examples/BGL_polyhedron_3/CMakeLists.txt +++ b/BGL/examples/BGL_polyhedron_3/CMakeLists.txt @@ -2,26 +2,18 @@ # This is the CMake script for compiling a set of CGAL applications. cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_polyhedron_3_Examples ) - - +project(BGL_polyhedron_3_Examples) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() +find_package(CGAL REQUIRED) # Boost and its components -find_package( Boost REQUIRED ) +find_package(Boost REQUIRED) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() @@ -34,21 +26,21 @@ endif() # Creating entries for all C++ files with "main" routine # ########################################################## -create_single_source_cgal_program( "distance.cpp" ) +create_single_source_cgal_program("distance.cpp") -create_single_source_cgal_program( "incident_vertices.cpp" ) +create_single_source_cgal_program("incident_vertices.cpp") -create_single_source_cgal_program( "kruskal.cpp" ) +create_single_source_cgal_program("kruskal.cpp") -create_single_source_cgal_program( "kruskal_with_stored_id.cpp" ) +create_single_source_cgal_program("kruskal_with_stored_id.cpp") -create_single_source_cgal_program( "normals.cpp" ) +create_single_source_cgal_program("normals.cpp") -create_single_source_cgal_program( "range.cpp" ) +create_single_source_cgal_program("range.cpp") -create_single_source_cgal_program( "transform_iterator.cpp" ) +create_single_source_cgal_program("transform_iterator.cpp") -create_single_source_cgal_program( "copy_polyhedron.cpp" ) +create_single_source_cgal_program("copy_polyhedron.cpp") find_package( OpenMesh QUIET ) @@ -70,4 +62,3 @@ if( METIS_FOUND ) message( STATUS "Examples that use the METIS library will not be compiled." ) endif() endif() - diff --git a/BGL/examples/BGL_surface_mesh/CMakeLists.txt b/BGL/examples/BGL_surface_mesh/CMakeLists.txt index c545ffa17da..f07081a0cd8 100644 --- a/BGL/examples/BGL_surface_mesh/CMakeLists.txt +++ b/BGL/examples/BGL_surface_mesh/CMakeLists.txt @@ -1,31 +1,22 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_surface_mesh_Examples ) +project(BGL_surface_mesh_Examples) - -find_package( CGAL QUIET ) - -if ( NOT CGAL_FOUND ) - message( STATUS "This project requires the CGAL library, and will not be compiled." ) - return() -endif() +find_package(CGAL REQUIRED) # include for local package -create_single_source_cgal_program( "prim.cpp" ) -create_single_source_cgal_program( "gwdwg.cpp" ) -create_single_source_cgal_program( "seam_mesh.cpp" ) -create_single_source_cgal_program( "write_inp.cpp" ) -create_single_source_cgal_program( "surface_mesh_dual.cpp" ) -create_single_source_cgal_program( "connected_components.cpp" ) - -find_package( METIS ) +create_single_source_cgal_program("prim.cpp") +create_single_source_cgal_program("gwdwg.cpp") +create_single_source_cgal_program("seam_mesh.cpp") +create_single_source_cgal_program("write_inp.cpp") +create_single_source_cgal_program("surface_mesh_dual.cpp") +create_single_source_cgal_program("connected_components.cpp") +find_package(METIS) if( METIS_FOUND ) - create_single_source_cgal_program( "surface_mesh_partition.cpp" ) target_include_directories( surface_mesh_partition PRIVATE ${METIS_INCLUDE_DIRS} ) target_link_libraries( surface_mesh_partition PRIVATE ${METIS_LIBRARIES} ) else() - message( STATUS "Examples that use the METIS library will not be compiled." ) + message(STATUS "Examples that use the METIS library will not be compiled.") endif() - diff --git a/BGL/examples/BGL_triangulation_2/CMakeLists.txt b/BGL/examples/BGL_triangulation_2/CMakeLists.txt index 55eb169ecff..9fa3903f234 100644 --- a/BGL/examples/BGL_triangulation_2/CMakeLists.txt +++ b/BGL/examples/BGL_triangulation_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_triangulation_2_Examples ) +project(BGL_triangulation_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/BGL/include/CGAL/boost/graph/Seam_mesh.h b/BGL/include/CGAL/boost/graph/Seam_mesh.h index 4919c73b42c..c74accc8586 100644 --- a/BGL/include/CGAL/boost/graph/Seam_mesh.h +++ b/BGL/include/CGAL/boost/graph/Seam_mesh.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -32,6 +33,7 @@ namespace CGAL { #ifndef DOXYGEN_RUNNING + template class Seam_mesh_halfedge_descriptor { @@ -86,8 +88,92 @@ public: return 2 * hash_value(hd.tmhd) + static_cast(hd.seam); } }; + +template +class Seam_mesh_vertex_descriptor +{ +public: + Seam_mesh_halfedge_descriptor hd; + + Seam_mesh_vertex_descriptor() { } + + Seam_mesh_vertex_descriptor(const Seam_mesh_halfedge_descriptor& h) + : hd(h) + { } + + bool operator==(const Seam_mesh_vertex_descriptor& other) const + { + return (hd == other.hd); + } + + bool operator!=(const Seam_mesh_vertex_descriptor& other) const + { + return (hd != other.hd); + } + + bool operator<(const Seam_mesh_vertex_descriptor& other) const + { + return hd < other.hd; + } + + operator HD() const + { + return hd; + } + +#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR + friend std::ostream& operator<<(std::ostream& os, const Seam_mesh_vertex_descriptor vd) + { + os << "seam mesh vertex: " << vd.hd; + return os; + } #endif + friend std::size_t hash_value(const Seam_mesh_vertex_descriptor& vd) + { + return hash_value(vd.hd.tmhd); + } +}; + +template +class Seam_mesh_edge_descriptor +{ +public: + Seam_mesh_halfedge_descriptor hd; + const SM* mesh_; + + Seam_mesh_edge_descriptor() : mesh_(nullptr) { } + + Seam_mesh_edge_descriptor(const Seam_mesh_halfedge_descriptor& hd, const SM* m) + : hd(hd), mesh_(m) + {} + + friend bool operator==(Seam_mesh_edge_descriptor e1, Seam_mesh_edge_descriptor e2) + { + return (e1.hd == e2.hd) || (e1.hd == e2.mesh_->opposite(e2.hd)); + } + + friend bool operator!=(Seam_mesh_edge_descriptor e1, Seam_mesh_edge_descriptor e2) + { + return ! (e1 == e2); + } + +#ifdef CGAL_SEAM_MESH_INSERT_OPERATOR + friend std::ostream& operator<<(std::ostream& os, const Seam_mesh_edge_descriptor& ed) + { + os << ed.hd; + return os; + } +#endif + + friend std::size_t hash_value(const Seam_mesh_edge_descriptor& ed) + { + return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd))); + } +}; + +#endif // DOXYGEN_RUNNING + /// \ingroup PkgBGLAdaptors /// /// This class is a data structure that takes a triangle mesh, further refered @@ -112,6 +198,10 @@ class Seam_mesh typedef Seam_mesh Self; public: + /// The underlying mesh type + typedef TM Triangle_mesh; + + // backward compatibility typedef TM TriangleMesh; public: @@ -187,23 +277,15 @@ public: class halfedge_descriptor { public: - TM_halfedge_descriptor tmhd; - bool seam; - /// %Default constructor - halfedge_descriptor() : tmhd(), seam(false) { } + halfedge_descriptor(); - halfedge_descriptor(TM_halfedge_descriptor tmhd, bool seam = false) - : tmhd(tmhd), seam(seam) - { } + /// Constructor from a halfedge of the underlying mesh + halfedge_descriptor(TM_halfedge_descriptor tmhd, bool seam = false); #ifdef CGAL_SEAM_MESH_INSERT_OPERATOR /// Print the halfedge and if it is on a seam. - friend std::ostream& operator<<(std::ostream& os, const halfedge_descriptor& hd) - { - os << hd.tmhd << ((hd.seam)?" on seam":""); - return os; - } + friend std::ostream& operator<<(std::ostream& os, const halfedge_descriptor& hd); #endif }; #else @@ -265,13 +347,13 @@ public: return halfedge_descriptor(*hd, seam); } }; -#endif +#endif // DOXYGEN_RUNNING +#ifdef DOXYGEN_RUNNING /// This class represents a vertex of the seam mesh. /// /// Implementation note: to properly duplicate vertices that are on seams, - /// a vertex_descriptor is in fact represented as a halfedge of the underlying - /// mesh. + /// a vertex_descriptor is in fact represented as a halfedge of the seam mesh. /// /// \cgalModels `Descriptor` /// \cgalModels `LessThanComparable` @@ -280,48 +362,20 @@ public: class vertex_descriptor { public: - halfedge_descriptor hd; - /// %Default constructor - vertex_descriptor() { } + vertex_descriptor(); - vertex_descriptor(const halfedge_descriptor& h) - : hd(h) - { } - - bool operator==(const vertex_descriptor& other) const - { - return (hd == other.hd); - } - - bool operator!=(const vertex_descriptor& other) const - { - return (hd != other.hd); - } - - bool operator<(const vertex_descriptor& other) const - { - return hd < other.hd; - } - - operator TM_halfedge_descriptor() const - { - return hd; - } + /// Constructor from a seam mesh halfedge + vertex_descriptor(const halfedge_descriptor& h); #ifdef CGAL_SEAM_MESH_INSERT_OPERATOR - friend std::ostream& operator<<(std::ostream& os, const vertex_descriptor vd) - { - os << "seam mesh vertex: " << vd.hd; - return os; - } + /// Print the seam mesh vertex. + friend std::ostream& operator<<(std::ostream& os, const vertex_descriptor vd); #endif - - friend std::size_t hash_value(const vertex_descriptor& vd) - { - return hash_value(vd.hd.tmhd); - } }; +#else + typedef Seam_mesh_vertex_descriptor vertex_descriptor; +#endif // iterator #ifndef DOXYGEN_RUNNING @@ -403,48 +457,24 @@ public: }; #endif +#ifdef DOXYGEN_RUNNING /// This class represents an edge of the seam mesh. /// /// \cgalModels `Descriptor` + /// \cgalModels `Hashable` /// class edge_descriptor { - public: - halfedge_descriptor hd; - const Self* mesh_; + /// %Default constructor + edge_descriptor(); #ifdef CGAL_SEAM_MESH_INSERT_OPERATOR - friend - std::ostream& operator<<(std::ostream& os, const edge_descriptor& ed) - { - os << ed.hd; - return os; - } + friend std::ostream& operator<<(std::ostream& os, const edge_descriptor& ed); #endif - - edge_descriptor() - : mesh_(nullptr) - {} - - edge_descriptor(const halfedge_descriptor& hd, const Self* m) - : hd(hd), mesh_(m) - {} - - friend bool operator==(edge_descriptor e1, edge_descriptor e2) - { - return (e1.hd == e2.hd) || (e1.hd == e2.mesh_->opposite(e2.hd)); - } - - friend bool operator!=(edge_descriptor e1, edge_descriptor e2) - { - return ! (e1 == e2); - } - - friend std::size_t hash_value(const edge_descriptor& ed) - { - return hash_value((std::min)(ed.hd, ed.mesh_->opposite(ed.hd))); - } }; +#else + typedef Seam_mesh_edge_descriptor edge_descriptor; +#endif #ifndef DOXYGEN_RUNNING // iterator @@ -1120,6 +1150,46 @@ public: } // namespace CGAL +#ifndef CGAL_CFG_NO_STD_HASH + +namespace std { + +template +struct hash > + : public CGAL::cpp98::unary_function, std::size_t> +{ + std::size_t operator()(const CGAL::Seam_mesh_vertex_descriptor& v) const + { + return hash_value(v); + } +}; + +template +struct hash > + : public CGAL::cpp98::unary_function, std::size_t> +{ + std::size_t operator()(const CGAL::Seam_mesh_halfedge_descriptor& h) const + { + return hash_value(h); + } +}; + +template +struct hash > + : public CGAL::cpp98::unary_function, std::size_t> +{ + std::size_t operator()(const CGAL::Seam_mesh_edge_descriptor& e) const + { + return hash_value(e); + } +}; + +// Seam_mesh::face_descriptor is equal to TM_face_descriptor so nothing to do + +} // namespace std + +#endif // CGAL_CFG_NO_STD_HASH + #include #endif //CGAL_SEAM_MESH_H diff --git a/BGL/include/CGAL/boost/graph/generators.h b/BGL/include/CGAL/boost/graph/generators.h index 389f9ba3308..151ffe1df50 100644 --- a/BGL/include/CGAL/boost/graph/generators.h +++ b/BGL/include/CGAL/boost/graph/generators.h @@ -483,15 +483,15 @@ make_regular_prism(typename boost::graph_traits::vertices_size_type nb_ve for(typename boost::graph_traits::vertices_size_type i=0; i < nb_vertices; ++i) { put(vpmap, vertices[i], - P(0.5*diameter * cos(i*precision*to_rad) + base_center.x(), + P(0.5*diameter * cos(to_double(FT(i)*precision*to_rad)) + base_center.x(), height+base_center.y(), - -0.5*diameter * sin(i*precision*to_rad) + base_center.z())); + -0.5*diameter * sin(to_double(FT(i)*precision*to_rad)) + base_center.z())); put(vpmap, vertices[i+nb_vertices], - P(0.5*diameter * cos(i*precision*to_rad) + base_center.x(), + P(0.5*diameter * cos(to_double(FT(i)*precision*to_rad)) + base_center.x(), base_center.y(), - -0.5*diameter * sin(i*precision*to_rad) + base_center.z())); + -0.5*diameter * sin(to_double(FT(i)*precision*to_rad)) + base_center.z())); } //fill faces @@ -589,9 +589,9 @@ make_pyramid(typename boost::graph_traits::vertices_size_type nb_vertices for(typename boost::graph_traits::vertices_size_type i=0; i void operator()(const PropertyTag, IndexPropertyMap, const Graph&) { // The property map is not writable; should never be here. - CGAL_assertion_msg(false, "You are trying to initialize a non-writable property map"); + CGAL_assertion_msg(false, "Initialization of a non-writable property map is impossible"); } }; @@ -171,7 +171,7 @@ IndexMap get_initialized_index_map_const(const IndexMap index_map, CGAL_USE(g); CGAL_USE(p); - // If you are passing a pmap via NPs, it must be initialized + // If a pmap is passed via NPs, it must be initialized CGAL_assertion(is_index_map_valid(p, index_map, g)); return index_map; @@ -185,7 +185,7 @@ IndexMap get_initialized_index_map(const IndexMap index_map, CGAL_USE(g); CGAL_USE(p); - // If you are passing a pmap via NPs, it must be initialized + // If a pmap is passed via NPs, it must be initialized CGAL_assertion(is_index_map_valid(p, index_map, g)); return index_map; diff --git a/BGL/include/CGAL/boost/graph/parameters_interface.h b/BGL/include/CGAL/boost/graph/parameters_interface.h index 3e25ee8ff6c..54f039ee345 100644 --- a/BGL/include/CGAL/boost/graph/parameters_interface.h +++ b/BGL/include/CGAL/boost/graph/parameters_interface.h @@ -102,16 +102,20 @@ CGAL_add_named_parameter(halfedges_keeper_t, halfedges_keeper, halfedges_keeper) CGAL_add_named_parameter(volume_threshold_t, volume_threshold, volume_threshold) CGAL_add_named_parameter(dry_run_t, dry_run, dry_run) CGAL_add_named_parameter(do_not_modify_t, do_not_modify, do_not_modify) +CGAL_add_named_parameter(allow_self_intersections_t, allow_self_intersections, allow_self_intersections) +CGAL_add_named_parameter(polyhedral_envelope_epsilon_t, polyhedral_envelope_epsilon, polyhedral_envelope_epsilon) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) CGAL_add_named_parameter(get_placement_policy_t, get_placement_policy, get_placement) +CGAL_add_named_parameter(filter_t, filter, filter) //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) CGAL_add_named_parameter(random_seed_t, random_seed, random_seed) CGAL_add_named_parameter(do_lock_mesh_t, do_lock_mesh, do_lock_mesh) CGAL_add_named_parameter(do_simplify_border_t, do_simplify_border, do_simplify_border) +CGAL_add_named_parameter(algorithm_t, algorithm, algorithm) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) @@ -150,6 +154,8 @@ CGAL_add_named_parameter(inspector_t, inspector, inspector) CGAL_add_named_parameter(logger_t, logger, logger) CGAL_add_named_parameter(pointmatcher_config_t, pointmatcher_config, pointmatcher_config) CGAL_add_named_parameter(adjacencies_t, adjacencies, adjacencies) +CGAL_add_named_parameter(scan_angle_t, scan_angle_map, scan_angle_map) +CGAL_add_named_parameter(scanline_id_t, scanline_id_map, scanline_id_map) // List of named parameters used in Surface_mesh_approximation package CGAL_add_named_parameter(verbose_level_t, verbose_level, verbose_level) diff --git a/BGL/include/CGAL/draw_face_graph.h b/BGL/include/CGAL/draw_face_graph.h new file mode 100644 index 00000000000..0bc8531ed03 --- /dev/null +++ b/BGL/include/CGAL/draw_face_graph.h @@ -0,0 +1,197 @@ +// Copyright (c) 2018-2020 GeometryFactory (France) +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Guillaume Damiand +// Laurent Rineau + +#ifndef CGAL_DRAW_FACE_GRAPH_H +#define CGAL_DRAW_FACE_GRAPH_H + +#ifdef CGAL_USE_BASIC_VIEWER + +#include +#include +#include + +namespace CGAL +{ + +// Default color functor; user can change it to have its own face color +struct DefaultColorFunctorFaceGraph +{ + template + CGAL::Color operator()(const Graph&, + typename boost::graph_traits::face_descriptor fh) const + { + if (fh==boost::graph_traits::null_face()) // use to get the mono color + return CGAL::Color(100, 125, 200); // R G B between 0-255 + + return get_random_color(CGAL::get_default_random()); + } +}; + +class SimpleFaceGraphViewerQt : public Basic_viewer_qt +{ + using Base = Basic_viewer_qt; + +public: + SimpleFaceGraphViewerQt(QWidget* parent) : + Base(parent, "", false, true, true, true, false), + m_compute_elements_impl([]{}) + { + } + + /// Construct the viewer. + /// @param amesh the surface mesh to view + /// @param title the title of the window + /// @param anofaces if true, do not draw faces (faces are not computed; this can be + /// usefull for very big object where this time could be long) + template + SimpleFaceGraphViewerQt(QWidget* parent, + const SM& amesh, + const char* title="Basic Surface_mesh Viewer", + bool anofaces=false) : + SimpleFaceGraphViewerQt(parent, amesh, title, anofaces, DefaultColorFunctorFaceGraph()) + { + } + + template + SimpleFaceGraphViewerQt(QWidget* parent, + const SM& amesh, + const char* title, + bool anofaces, + ColorFunctor fcolor) : + // First draw: no vertex; edges, faces; mono-color; inverse normal + Base(parent, title, false, true, true, true, false), + m_compute_elements_impl(compute_elements_functor(amesh, anofaces, fcolor)) + { + } + + void init() override { + compute_elements(); + Base::init(); + } + + void compute_elements() { + m_compute_elements_impl(); + } + + template + void set_face_graph(const SM& amesh, + bool anofaces, + ColorFunctor fcolor) { + m_compute_elements_impl = compute_elements_functor(amesh, anofaces, fcolor); + } + + template + void set_face_graph(const SM& amesh, + bool anofaces=false) { + set_mesh(amesh, anofaces, DefaultColorFunctorFaceGraph()); + } +protected: + template + std::function + compute_elements_functor(const SM& sm, + bool anofaces, + ColorFunctor fcolor) + { + using Point = + typename boost::property_map_value::type; + using Kernel = typename CGAL::Kernel_traits::Kernel; + using Vector = typename Kernel::Vector_3; + + auto vnormals = get(CGAL::dynamic_vertex_property_t(), sm); + auto point_pmap = get(CGAL::vertex_point, sm); + for (auto v : vertices(sm)) + { + Vector n(NULL_VECTOR); + int i=0; + for (auto h : halfedges_around_target(halfedge(v, sm), sm)) + { + if (!is_border(h, sm)) + { + Vector ni = CGAL::cross_product( + Vector(get(point_pmap, source(h, sm)), get(point_pmap, target(h, sm))), + Vector(get(point_pmap, target(h, sm)), get(point_pmap, target(next(h, sm), sm)))); + if (ni != NULL_VECTOR) + { + n+=ni; + ++i; + } + } + } + put(vnormals, v, n/i); + } + + // This function return a lambda expression, type-erased in a + // `std::function` object. + return [this, &sm, vnormals, anofaces, fcolor, point_pmap]() + { + this->clear(); + + if (!anofaces) + { + for (auto fh: faces(sm)) + { + if (fh!=boost::graph_traits::null_face()) + { + CGAL::Color c=fcolor(sm, fh); + face_begin(c); + auto hd=halfedge(fh, sm); + const auto first_hd = hd; + do + { + auto v = source(hd, sm); + add_point_in_face(get(point_pmap, v), get(vnormals, v)); + hd=next(hd, sm); + } + while(hd!=first_hd); + face_end(); + } + } + } + + for (auto e: edges(sm)) + { + add_segment(get(point_pmap, source(halfedge(e, sm), sm)), + get(point_pmap, target(halfedge(e, sm), sm))); + } + + for (auto v: vertices(sm)) + { + this->add_point(get(point_pmap, v)); + } + }; + } + + void keyPressEvent(QKeyEvent *e) override + { + // Test key pressed: + // const ::Qt::KeyboardModifiers modifiers = e->modifiers(); + // if ((e->key()==Qt::Key_PageUp) && (modifiers==Qt::NoButton)) { ... } + + // Call: * compute_elements() if the model changed, followed by + // * redraw() if some viewing parameters changed that implies some + // modifications of the buffers + // (eg. type of normal, color/mono) + // * update() just to update the drawing + + // Call the base method to process others/classicals key + Base::keyPressEvent(e); + } + +protected: + std::function m_compute_elements_impl; +}; + +} // End namespace CGAL + +#endif // CGAL_USE_BASIC_VIEWER + +#endif // CGAL_DRAW_SURFACE_MESH_H diff --git a/BGL/package_info/BGL/dependencies b/BGL/package_info/BGL/dependencies index ebc36eadd85..7cf027b2c48 100644 --- a/BGL/package_info/BGL/dependencies +++ b/BGL/package_info/BGL/dependencies @@ -1,19 +1,13 @@ Algebraic_foundations -Arithmetic_kernel BGL Cartesian_kernel Circulator Distance_2 Distance_3 -Filtered_kernel Hash_map -Homogeneous_kernel Installation -Intersections_2 -Intersections_3 Interval_support Kernel_23 -Kernel_d Modular_arithmetic Number_types Profiling_tools diff --git a/BGL/test/BGL/CMakeLists.txt b/BGL/test/BGL/CMakeLists.txt index dfe324a32af..8d5b0e7b652 100644 --- a/BGL/test/BGL/CMakeLists.txt +++ b/BGL/test/BGL/CMakeLists.txt @@ -2,119 +2,110 @@ # This is the CMake script for compiling a set of CGAL applications. cmake_minimum_required(VERSION 3.1...3.15) -project( BGL_Tests ) - - - - +project(BGL_Tests) # CGAL and its components -find_package( CGAL QUIET COMPONENTS ) - -if ( NOT CGAL_FOUND ) - - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() - -endif() +find_package(CGAL REQUIRED) # Boost and its components -find_package( Boost ) +find_package(Boost) -if ( NOT Boost_FOUND ) - message(STATUS "This project requires the Boost library, and will not be compiled.") +if(NOT Boost_FOUND) + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() endif() -find_package( OpenMesh QUIET ) +find_package(OpenMesh QUIET) -if ( OpenMesh_FOUND ) - include( UseOpenMesh ) - add_definitions( -DCGAL_USE_OPENMESH ) +if(OpenMesh_FOUND) + include(UseOpenMesh) + add_definitions(-DCGAL_USE_OPENMESH) else() message(STATUS "Examples that use OpenMesh will not be compiled.") endif() - - # include for local package # Creating entries for all .cpp/.C files with "main" routine # ########################################################## if(OpenMesh_FOUND) - create_single_source_cgal_program( "graph_concept_OpenMesh.cpp" ) - target_link_libraries( graph_concept_OpenMesh PRIVATE ${OPENMESH_LIBRARIES} ) + create_single_source_cgal_program("graph_concept_OpenMesh.cpp") + target_link_libraries(graph_concept_OpenMesh PRIVATE ${OPENMESH_LIBRARIES}) endif() -create_single_source_cgal_program( "next.cpp" ) +create_single_source_cgal_program("test_split.cpp") -create_single_source_cgal_program( "test_circulator.cpp" ) +create_single_source_cgal_program("next.cpp") -create_single_source_cgal_program( "test_Gwdwg.cpp" ) +create_single_source_cgal_program("test_circulator.cpp") -create_single_source_cgal_program( "test_bgl_dual.cpp" ) +create_single_source_cgal_program("test_Gwdwg.cpp") -create_single_source_cgal_program( "graph_concept_Polyhedron_3.cpp" ) +create_single_source_cgal_program("test_bgl_dual.cpp") -create_single_source_cgal_program( "graph_concept_Dual.cpp" ) +create_single_source_cgal_program("graph_concept_Polyhedron_3.cpp") -create_single_source_cgal_program( "graph_concept_Triangulation_2.cpp" ) +create_single_source_cgal_program("graph_concept_Dual.cpp") -create_single_source_cgal_program( "graph_concept_Surface_mesh.cpp" ) +create_single_source_cgal_program("graph_concept_Triangulation_2.cpp") -create_single_source_cgal_program( "graph_concept_Seam_mesh_Surface_mesh.cpp" ) +create_single_source_cgal_program("graph_concept_Surface_mesh.cpp") -create_single_source_cgal_program( "graph_concept_Gwdwg_Surface_mesh.cpp" ) +create_single_source_cgal_program("graph_concept_Seam_mesh_Surface_mesh.cpp") -create_single_source_cgal_program( "graph_concept_Linear_cell_complex.cpp" ) +create_single_source_cgal_program("graph_concept_Gwdwg_Surface_mesh.cpp") -create_single_source_cgal_program( "graph_concept_Arrangement_2.cpp" ) +create_single_source_cgal_program("graph_concept_Linear_cell_complex.cpp") + +create_single_source_cgal_program("graph_concept_Arrangement_2.cpp") create_single_source_cgal_program( "graph_concept_Derived.cpp" ) create_single_source_cgal_program( "test_clear.cpp" ) -create_single_source_cgal_program( "test_helpers.cpp" ) +create_single_source_cgal_program("test_helpers.cpp") -create_single_source_cgal_program( "test_Has_member_clear.cpp" ) +create_single_source_cgal_program("test_Has_member_clear.cpp") -create_single_source_cgal_program( "test_Has_member_id.cpp" ) +create_single_source_cgal_program("test_Has_member_id.cpp") -create_single_source_cgal_program( "test_cgal_bgl_named_params.cpp" ) +create_single_source_cgal_program("test_cgal_bgl_named_params.cpp") -create_single_source_cgal_program( "test_bgl_read_write.cpp" ) +create_single_source_cgal_program("test_bgl_read_write.cpp") -create_single_source_cgal_program( "graph_concept_Face_filtered_graph.cpp" ) +create_single_source_cgal_program("graph_concept_Face_filtered_graph.cpp") -create_single_source_cgal_program( "test_Manifold_face_removal.cpp") +create_single_source_cgal_program("test_Manifold_face_removal.cpp") -create_single_source_cgal_program( "test_Regularize_face_selection_borders.cpp") +create_single_source_cgal_program("test_Regularize_face_selection_borders.cpp") -create_single_source_cgal_program( "test_Face_filtered_graph.cpp" ) +create_single_source_cgal_program("test_Face_filtered_graph.cpp") -create_single_source_cgal_program( "test_Euler_operations.cpp" ) +create_single_source_cgal_program("test_Euler_operations.cpp") create_single_source_cgal_program( "test_test_face.cpp" ) create_single_source_cgal_program( "test_Collapse_edge.cpp" ) -create_single_source_cgal_program( "test_graph_traits.cpp" ) +create_single_source_cgal_program("test_graph_traits.cpp") -create_single_source_cgal_program( "test_Properties.cpp" ) +create_single_source_cgal_program("test_Properties.cpp") -create_single_source_cgal_program( "test_wrl.cpp" ) +create_single_source_cgal_program("test_wrl.cpp") -create_single_source_cgal_program( "bench_read_from_stream_vs_add_face_and_add_faces.cpp" ) +create_single_source_cgal_program( + "bench_read_from_stream_vs_add_face_and_add_faces.cpp") create_single_source_cgal_program( "graph_traits_inheritance.cpp" ) if(OpenMesh_FOUND) - target_link_libraries( test_clear PRIVATE ${OPENMESH_LIBRARIES}) - target_link_libraries( test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES}) - target_link_libraries( test_Collapse_edge PRIVATE ${OPENMESH_LIBRARIES}) - target_link_libraries( test_Face_filtered_graph PRIVATE ${OPENMESH_LIBRARIES}) - target_link_libraries( test_graph_traits PRIVATE ${OPENMESH_LIBRARIES} ) - target_link_libraries( test_Properties PRIVATE ${OPENMESH_LIBRARIES}) - target_link_libraries( test_bgl_read_write PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_clear PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_Euler_operations PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_Collapse_edge PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_Face_filtered_graph PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_graph_traits PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_Properties PRIVATE ${OPENMESH_LIBRARIES}) + target_link_libraries(test_bgl_read_write PRIVATE ${OPENMESH_LIBRARIES}) endif() diff --git a/BGL/test/BGL/split.cin b/BGL/test/BGL/split.cin deleted file mode 100644 index 484dc3db9ac..00000000000 --- a/BGL/test/BGL/split.cin +++ /dev/null @@ -1,6 +0,0 @@ -5 -2 1 1 1 -1 1 1 0 -1 0 2 0 -2 1 2 0 -3 1 2 1 \ No newline at end of file diff --git a/BGL/test/BGL/split.cpp b/BGL/test/BGL/split.cpp deleted file mode 100644 index 7df61a985a9..00000000000 --- a/BGL/test/BGL/split.cpp +++ /dev/null @@ -1,113 +0,0 @@ - -#include -#include -#include -#include -#include - -typedef CGAL::Simple_cartesian K; -typedef K::Point_2 Point_2; - -typedef boost::adjacency_list < boost::listS, - boost::vecS, - boost::undirectedS, - Point_2 > G; - -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; - -typedef std::vector Polyline_2; - -struct Is_terminal -{ - template - bool operator ()(VertexDescriptor vd , const Graph& g ) - { - return false; // degree(vd,g) != 2; is a bad test in case of parallel edges - } -}; - - -template -struct Polyline_visitor -{ - std::list& polylines; - const Graph& points_pmap; - - Polyline_visitor(std::list& lines, - const Graph& points_property_map) - : polylines(lines), - points_pmap(points_property_map) - {} - - void start_new_polyline() - { - Polyline_2 V; - polylines.push_back(V); - } - - void add_node(typename boost::graph_traits::vertex_descriptor vd) - { - Polyline_2& polyline = polylines.back(); - polyline.push_back(points_pmap[vd]); - } -}; - - -int main() -{ - G g; - - std::list polylines; - Polyline_visitor polyline_visitor(polylines, g); - std::map p2vd; - - int n; - std::cin >> n; // number of segments - - - Point_2 p, q; - vertex_descriptor vdp, vdq; - for(int i=0; i < n; i++){ - std::cin >> p >> q; - - if(p2vd.find(p) == p2vd.end()){ - vdp = add_vertex(g); - g[vdp] = p; - p2vd[p] = vdp; - } else { - vdp = p2vd[p]; - } - if(p2vd.find(q) == p2vd.end()){ - vdq = add_vertex(g); - g[vdq] = q; - p2vd[q] = vdq; - } else { - vdq = p2vd[q]; - } - boost::add_edge(vdp, vdq, g); - } - - CGAL::split_graph_into_polylines( g, - polyline_visitor, - Is_terminal() ); - std::cout.precision(17); - - - for(std::list::iterator it = polylines.begin(); it!= polylines.end(); ++it){ - Polyline_2& poly = *it; - std::size_t n; - if(poly.front() == poly.back()){ - std::cout << "POLYGON" << std::endl; - n = poly.size() -1; - }else{ - std::cout << "POLYLINE" << std::endl; - n = poly.size(); - } - for(std::size_t j=0; j < n; j++){ - std::cout << poly[j] << std::endl; - } - std::cout << std::endl; - } - - return 0; -} diff --git a/BGL/test/BGL/test_cgal_bgl_named_params.cpp b/BGL/test/BGL/test_cgal_bgl_named_params.cpp index 1a2c89555b7..f7bf797a8da 100644 --- a/BGL/test/BGL/test_cgal_bgl_named_params.cpp +++ b/BGL/test/BGL/test_cgal_bgl_named_params.cpp @@ -98,6 +98,8 @@ void test(const NamedParameters& np) assert(get_parameter(np, CGAL::internal_np::halfedges_keeper).v == 62); assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 64); assert(get_parameter(np, CGAL::internal_np::do_not_modify).v == 65); + assert(get_parameter(np, CGAL::internal_np::allow_self_intersections).v == 66); + assert(get_parameter(np, CGAL::internal_np::polyhedral_envelope_epsilon).v == 67); assert(get_parameter(np, CGAL::internal_np::maximum_number_of_faces).v == 78910); // Named parameters that we use in the package 'Surface Mesh Simplification' @@ -186,6 +188,8 @@ void test(const NamedParameters& np) check_same_type<55>(get_parameter(np, CGAL::internal_np::use_Delaunay_flips)); check_same_type<56>(get_parameter(np, CGAL::internal_np::use_safety_constraints)); check_same_type<65>(get_parameter(np, CGAL::internal_np::do_not_modify)); + check_same_type<66>(get_parameter(np, CGAL::internal_np::allow_self_intersections)); + check_same_type<67>(get_parameter(np, CGAL::internal_np::polyhedral_envelope_epsilon)); check_same_type<12340>(get_parameter(np, CGAL::internal_np::do_self_intersection_tests)); check_same_type<12341>(get_parameter(np, CGAL::internal_np::do_orientation_tests)); @@ -219,6 +223,7 @@ void test(const NamedParameters& np) check_same_type<36>(get_parameter(np, CGAL::internal_np::face_normal)); check_same_type<37>(get_parameter(np, CGAL::internal_np::random_seed)); check_same_type<38>(get_parameter(np, CGAL::internal_np::do_project)); + check_same_type<456>(get_parameter(np, CGAL::internal_np::algorithm)); // Internal named parameters check_same_type<39>(get_parameter(np, CGAL::internal_np::weight_calculator)); @@ -265,6 +270,8 @@ void test(const NamedParameters& np) check_same_type<9032>(get_parameter(np, CGAL::internal_np::inspector)); check_same_type<9033>(get_parameter(np, CGAL::internal_np::logger)); check_same_type<9034>(get_parameter(np, CGAL::internal_np::maximum_normal_deviation)); + check_same_type<9035>(get_parameter(np, CGAL::internal_np::scan_angle_map)); + check_same_type<9036>(get_parameter(np, CGAL::internal_np::scanline_id_map)); } int main() @@ -318,6 +325,7 @@ int main() .face_normal_map(A<36>(36)) .random_seed(A<37>(37)) .do_project(A<38>(38)) + .algorithm(A<456>(456)) .weight_calculator(A<39>(39)) .preserve_genus(A<40>(40)) .verbosity_level(A<41>(41)) @@ -356,6 +364,8 @@ int main() .use_convex_hull(A<63>(63)) .do_simplify_border(A<64>(64)) .do_not_modify(A<65>(65)) + .allow_self_intersections(A<66>(66)) + .polyhedral_envelope_epsilon(A<67>(67)) .point_map(A<9000>(9000)) .query_point_map(A<9001>(9001)) .normal_map(A<9002>(9002)) @@ -391,6 +401,8 @@ int main() .inspector(A<9032>(9032)) .logger(A<9033>(9033)) .maximum_normal_deviation(A<9034>(9034)) + .scan_angle_map(A<9035>(9035)) + .scanline_id_map(A<9036>(9036)) .maximum_number_of_faces(A<78910>(78910)) ); return EXIT_SUCCESS; diff --git a/BGL/test/BGL/test_split.cpp b/BGL/test/BGL/test_split.cpp new file mode 100644 index 00000000000..f9b6fff3ced --- /dev/null +++ b/BGL/test/BGL/test_split.cpp @@ -0,0 +1,111 @@ + +#include +#include + +#include + +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef K::Point_2 Point_2; + + +typedef boost::adjacency_list Graph; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +typedef std::map Point_vertex_map; + +typedef std::vector Polyline_2; + + +// inserts a polyline into a graph +void insert(const std::vector& poly, Graph& graph, Point_vertex_map& pvmap) +{ + vertex_descriptor u, v; + for (std::size_t i = 0; i < poly.size(); i++) { + // check if the point is not yet in the graph + if (pvmap.find(poly[i]) == pvmap.end()) { + v = add_vertex(graph); + pvmap[poly[i]] = v; + } + else { + v = pvmap[poly[i]]; + } + graph[v] = poly[i]; // associate the point to the vertex + if (i != 0) { + add_edge(u, v, graph); + } + u = v; + } +} + +template +struct Polyline_visitor +{ + std::list& polylines; + const Graph& points_pmap; + + Polyline_visitor(std::list& lines, + const Graph& points_property_map) + : polylines(lines), + points_pmap(points_property_map) + {} + + void start_new_polyline() + { + Polyline_2 V; + polylines.push_back(V); + } + + void add_node(typename boost::graph_traits::vertex_descriptor vd) + { + Polyline_2& polyline = polylines.back(); + polyline.push_back(points_pmap[vd]); + } + + void end_polyline() + {} + +}; + + +int main() +{ + Polyline_2 polyA = { Point_2(0,0), Point_2(1,0), Point_2(2,0), Point_2(3,0), Point_2(4,0)}; + Polyline_2 polyB = { Point_2(1,-1), Point_2(1,0), Point_2(2,0), Point_2(2,1), Point_2(2,2) }; + + Graph graph; + Point_vertex_map pvmap; + + insert(polyA, graph, pvmap); + insert(polyB, graph, pvmap); + + std::list polylines; + Polyline_visitor polyline_visitor(polylines, graph); + + CGAL::split_graph_into_polylines( graph, + polyline_visitor); + + + for(std::list::iterator it = polylines.begin(); it!= polylines.end(); ++it){ + Polyline_2& poly = *it; + std::size_t n; + if(poly.front() == poly.back()){ + std::cout << "POLYGON" << std::endl; + n = poly.size() -1; + }else{ + std::cout << "POLYLINE" << std::endl; + n = poly.size(); + } + for(std::size_t j=0; j < n; j++){ + std::cout << poly[j] << std::endl; + } + std::cout << std::endl; + } + + return 0; + +} diff --git a/Barycentric_coordinates_2/examples/Barycentric_coordinates_2/CMakeLists.txt b/Barycentric_coordinates_2/examples/Barycentric_coordinates_2/CMakeLists.txt index fe29d09d8af..dd081fc1f23 100644 --- a/Barycentric_coordinates_2/examples/Barycentric_coordinates_2/CMakeLists.txt +++ b/Barycentric_coordinates_2/examples/Barycentric_coordinates_2/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Barycentric_coordinates_2_Examples ) +project(Barycentric_coordinates_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Segment_coordinates_2.h b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Segment_coordinates_2.h index 9738eba83b7..42dca2848e5 100644 --- a/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Segment_coordinates_2.h +++ b/Barycentric_coordinates_2/include/CGAL/Barycentric_coordinates_2/Segment_coordinates_2.h @@ -199,10 +199,10 @@ private: // Global functions /*! - \anchor seg_coord_global * \relates Segment_coordinates_2 * This is a global function that takes both vertices of a segment and computes segment coordinates at a given query point with respect to these vertices. + \anchor seg_coord_global \tparam Traits must be a model of the concept `BarycentricTraits_2`. */ diff --git a/Barycentric_coordinates_2/test/Barycentric_coordinates_2/CMakeLists.txt b/Barycentric_coordinates_2/test/Barycentric_coordinates_2/CMakeLists.txt index 1e5b96696b2..3af8199b60a 100644 --- a/Barycentric_coordinates_2/test/Barycentric_coordinates_2/CMakeLists.txt +++ b/Barycentric_coordinates_2/test/Barycentric_coordinates_2/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Barycentric_coordinates_2_Tests ) +project(Barycentric_coordinates_2_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Boolean_set_operations_2/archive/demo/Boolean_set_operations_2_GraphicsView/CMakeLists.txt b/Boolean_set_operations_2/archive/demo/Boolean_set_operations_2_GraphicsView/CMakeLists.txt index dac559d6846..b02cec7624c 100644 --- a/Boolean_set_operations_2/archive/demo/Boolean_set_operations_2_GraphicsView/CMakeLists.txt +++ b/Boolean_set_operations_2/archive/demo/Boolean_set_operations_2_GraphicsView/CMakeLists.txt @@ -2,42 +2,49 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.15) -project( Boolean_set_operations_2_GraphicsView_Demo ) +project(Boolean_set_operations_2_GraphicsView_Demo) if(NOT POLICY CMP0070 AND POLICY CMP0053) # Only set CMP0053 to OLD with CMake<3.10, otherwise there is a warning. cmake_policy(SET CMP0053 OLD) endif() -find_package(CGAL COMPONENTS Qt5 Core ) +find_package(CGAL COMPONENTS Qt5 Core) -set( QT_USE_QTMAIN TRUE ) +set(QT_USE_QTMAIN TRUE) find_package(Qt5 QUIET COMPONENTS Widgets Script Svg) -include_directories (BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include ) +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include) -if ( CGAL_FOUND AND CGAL_Qt5_FOUND AND Qt5_FOUND AND CGAL_Core_FOUND ) -set(CMAKE_AUTOMOC ON) +if(CGAL_Qt5_FOUND + AND Qt5_FOUND + AND CGAL_Core_FOUND) + set(CMAKE_AUTOMOC ON) # UI files (Qt Designer files) - qt5_wrap_ui( CDT_UI_FILES boolean_operations_2.ui ) + qt5_wrap_ui(CDT_UI_FILES boolean_operations_2.ui) # qrc files (resources files, that contain icons, at least) - qt5_add_resources ( CGAL_Qt5_RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/boolean_operations_2.qrc ) + qt5_add_resources(CGAL_Qt5_RESOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/boolean_operations_2.qrc) # use the Qt MOC preprocessor on classes that derives from QObject - # The executable itself. - add_executable ( boolean_operations_2 ${CMAKE_CURRENT_SOURCE_DIR}/boolean_operations_2.cpp ${CGAL_Qt5_MOC_FILES} ${CDT_UI_FILES} ${CGAL_Qt5_RESOURCE_FILES} ) + add_executable( + boolean_operations_2 + ${CMAKE_CURRENT_SOURCE_DIR}/boolean_operations_2.cpp ${CGAL_Qt5_MOC_FILES} + ${CDT_UI_FILES} ${CGAL_Qt5_RESOURCE_FILES}) # Link with Qt libraries - target_link_libraries( boolean_operations_2 Qt5::Widgets Qt5::Script Qt5::Svg ) + target_link_libraries(boolean_operations_2 Qt5::Widgets Qt5::Script Qt5::Svg) # Link with CGAL - target_link_libraries( boolean_operations_2 ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES}) + target_link_libraries(boolean_operations_2 ${CGAL_LIBRARIES} + ${CGAL_3RD_PARTY_LIBRARIES}) else() - message(STATUS "NOTICE: This demo requires CGAL and Qt5, and will not be compiled.") + message( + STATUS "NOTICE: This demo requires CGAL and Qt5, and will not be compiled.") endif() diff --git a/Boolean_set_operations_2/examples/Boolean_set_operations_2/CMakeLists.txt b/Boolean_set_operations_2/examples/Boolean_set_operations_2/CMakeLists.txt index f3a59f95641..38c8d696c74 100644 --- a/Boolean_set_operations_2/examples/Boolean_set_operations_2/CMakeLists.txt +++ b/Boolean_set_operations_2/examples/Boolean_set_operations_2/CMakeLists.txt @@ -1,26 +1,18 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Boolean_set_operations_2_Examples ) +project(Boolean_set_operations_2_Examples) +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core) - -if ( CGAL_FOUND ) - - include(${CGAL_USE_FILE}) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() +include(${CGAL_USE_FILE}) +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Polygon_2_curve_iterator.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Polygon_2_curve_iterator.h index 833f9afd571..0da7fcd55f3 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Polygon_2_curve_iterator.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/Polygon_2_curve_iterator.h @@ -52,7 +52,7 @@ public: typedef Polygon_ Polygon; - typedef typename Polygon::Edge_const_iterator Edge_const_iterator; + typedef typename Polygon::Vertex_pair_iterator Edge_const_iterator; typedef typename Edge_const_iterator::difference_type difference_type; private: @@ -78,7 +78,7 @@ public: X_monotone_curve_2 operator*() { - return X_monotone_curve_2(*m_curr_edge); + return X_monotone_curve_2(m_curr_edge->first, m_curr_edge->second); } Polygon_2_curve_ptr operator->() diff --git a/Boolean_set_operations_2/include/CGAL/Gps_segment_traits_2.h b/Boolean_set_operations_2/include/CGAL/Gps_segment_traits_2.h index af6aa17c22e..3704f08aa67 100644 --- a/Boolean_set_operations_2/include/CGAL/Gps_segment_traits_2.h +++ b/Boolean_set_operations_2/include/CGAL/Gps_segment_traits_2.h @@ -103,8 +103,8 @@ public: std::pair operator()(const General_polygon_2& pgn) const { - Curve_const_iterator c_begin(&pgn, pgn.edges_begin()); - Curve_const_iterator c_end(&pgn, pgn.edges_end()); + Curve_const_iterator c_begin(&pgn, pgn.vertex_pairs_begin()); + Curve_const_iterator c_end(&pgn, pgn.vertex_pairs_end()); return (std::make_pair(c_begin, c_end)); } diff --git a/Boolean_set_operations_2/test/Boolean_set_operations_2/CMakeLists.txt b/Boolean_set_operations_2/test/Boolean_set_operations_2/CMakeLists.txt index f346e2183ec..166a39cef9a 100644 --- a/Boolean_set_operations_2/test/Boolean_set_operations_2/CMakeLists.txt +++ b/Boolean_set_operations_2/test/Boolean_set_operations_2/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Boolean_set_operations_2_Tests ) +project(Boolean_set_operations_2_Tests) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_sphere_d.h b/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_sphere_d.h index ca5a9956ea5..82b106c9971 100644 --- a/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_sphere_d.h +++ b/Bounding_volumes/doc/Bounding_volumes/CGAL/Min_sphere_d.h @@ -68,7 +68,7 @@ each take linear time. \cgalHeading{Example} -\cgalExample{Min_sphere_d/min_sphere_homogeneous_d.cpp} +\cgalExample{Min_sphere_d/min_sphere_homogeneous_3.cpp} */ template< typename Traits > diff --git a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt index 9c066bd6cf4..7e50747fa0f 100644 --- a/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Approximate_min_ellipsoid_d/CMakeLists.txt @@ -1,31 +1,25 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Approximate_min_ellipsoid_d_Examples ) +project(Approximate_min_ellipsoid_d_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) +# Use Eigen +find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) +include(CGAL_Eigen_support) -if ( CGAL_FOUND ) - - # Use Eigen - find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - include(CGAL_Eigen_support) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR TARGET CGAL::Eigen_support) - get_filename_component(target ${cppfile} NAME_WE) - add_executable(${target} ${cppfile}) - if (TARGET CGAL::Eigen_support) - target_link_libraries(${target} CGAL::CGAL CGAL::Eigen_support) - else() - target_link_libraries(${target} CGAL::CGAL) - endif() +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + if(NOT (${cppfile} STREQUAL "ellipsoid.cpp") OR TARGET CGAL::Eigen_support) + get_filename_component(target ${cppfile} NAME_WE) + create_single_source_cgal_program(${cppfile}) + if(TARGET CGAL::Eigen_support) + target_link_libraries(${target} PRIVATE CGAL::CGAL CGAL::Eigen_support) + else() + target_link_libraries(${target} PRIVATE CGAL::CGAL) endif() - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() + endif() +endforeach() diff --git a/Bounding_volumes/examples/Min_annulus_d/CMakeLists.txt b/Bounding_volumes/examples/Min_annulus_d/CMakeLists.txt index d6c37a90755..ad8fe4ddf0b 100644 --- a/Bounding_volumes/examples/Min_annulus_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_annulus_d/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_annulus_d_Examples ) +project(Min_annulus_d_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Min_circle_2/CMakeLists.txt b/Bounding_volumes/examples/Min_circle_2/CMakeLists.txt index 5de341bd9de..2ff0b1cff21 100644 --- a/Bounding_volumes/examples/Min_circle_2/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_circle_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_circle_2_Examples ) +project(Min_circle_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Min_ellipse_2/CMakeLists.txt b/Bounding_volumes/examples/Min_ellipse_2/CMakeLists.txt index 2cd8f3660b5..6d361aa34df 100644 --- a/Bounding_volumes/examples/Min_ellipse_2/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_ellipse_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_ellipse_2_Examples ) +project(Min_ellipse_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Min_quadrilateral_2/CMakeLists.txt b/Bounding_volumes/examples/Min_quadrilateral_2/CMakeLists.txt index ff63e20a54e..c953eb3cd15 100644 --- a/Bounding_volumes/examples/Min_quadrilateral_2/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_quadrilateral_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_quadrilateral_2_Examples ) +project(Min_quadrilateral_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Min_sphere_d/CMakeLists.txt b/Bounding_volumes/examples/Min_sphere_d/CMakeLists.txt index d6192ef5da1..bbf53300d8c 100644 --- a/Bounding_volumes/examples/Min_sphere_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_sphere_d/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_sphere_d_Examples ) +project(Min_sphere_d_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Min_sphere_of_spheres_d/CMakeLists.txt b/Bounding_volumes/examples/Min_sphere_of_spheres_d/CMakeLists.txt index 1e04215d3b6..de68529c5cd 100644 --- a/Bounding_volumes/examples/Min_sphere_of_spheres_d/CMakeLists.txt +++ b/Bounding_volumes/examples/Min_sphere_of_spheres_d/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Min_sphere_of_spheres_d_Examples ) +project(Min_sphere_of_spheres_d_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/examples/Rectangular_p_center_2/CMakeLists.txt b/Bounding_volumes/examples/Rectangular_p_center_2/CMakeLists.txt index 52756958264..0e43e5b4e8b 100644 --- a/Bounding_volumes/examples/Rectangular_p_center_2/CMakeLists.txt +++ b/Bounding_volumes/examples/Rectangular_p_center_2/CMakeLists.txt @@ -1,20 +1,13 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Rectangular_p_center_2_Examples ) +project(Rectangular_p_center_2_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt index 5a29e19f887..37a505cf115 100644 --- a/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt +++ b/Bounding_volumes/test/Bounding_volumes/CMakeLists.txt @@ -1,37 +1,31 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Bounding_volumes_Tests ) +project(Bounding_volumes_Tests) +find_package(CGAL REQUIRED COMPONENTS Core) -find_package(CGAL QUIET COMPONENTS Core ) +include(${CGAL_USE_FILE}) -if ( CGAL_FOUND ) +# Use Eigen +find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) +include(CGAL_Eigen_support) - include(${CGAL_USE_FILE}) - - # Use Eigen - find_package(Eigen3 3.1.0 QUIET) #(3.1.0 or greater) - include(CGAL_Eigen_support) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") OR TARGET CGAL::Eigen_support) - get_filename_component(target ${cppfile} NAME_WE) - add_executable(${target} ${cppfile}) - if (TARGET CGAL::Eigen_support) - target_link_libraries(${target} CGAL::CGAL CGAL::Eigen_support) - else() - target_link_libraries(${target} CGAL::CGAL) - endif() +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + if(NOT (${cppfile} STREQUAL "Approximate_min_ellipsoid_d.cpp") + OR TARGET CGAL::Eigen_support) + get_filename_component(target ${cppfile} NAME_WE) + create_single_source_cgal_program(${cppfile}) + if(TARGET CGAL::Eigen_support) + target_link_libraries(${target} PRIVATE CGAL::CGAL CGAL::Eigen_support) + else() + target_link_libraries(${target} PRIVATE CGAL::CGAL) endif() - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() + endif() +endforeach() diff --git a/Box_intersection_d/examples/Box_intersection_d/CMakeLists.txt b/Box_intersection_d/examples/Box_intersection_d/CMakeLists.txt index 6b17fe83e29..8c14f8e3813 100644 --- a/Box_intersection_d/examples/Box_intersection_d/CMakeLists.txt +++ b/Box_intersection_d/examples/Box_intersection_d/CMakeLists.txt @@ -1,24 +1,16 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Box_intersection_d_Examples ) +project(Box_intersection_d_Examples) +find_package(CGAL REQUIRED) -find_package(CGAL QUIET) - -if ( CGAL_FOUND ) - - # create a target per cppfile - file(GLOB cppfiles RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) - foreach(cppfile ${cppfiles}) - create_single_source_cgal_program( "${cppfile}" ) - endforeach() - -else() - - message(STATUS "This program requires the CGAL library, and will not be compiled.") - -endif() - +# create a target per cppfile +file( + GLOB cppfiles + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) +foreach(cppfile ${cppfiles}) + create_single_source_cgal_program("${cppfile}") +endforeach() diff --git a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt index de7955c4208..5d214d0151d 100644 --- a/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt +++ b/Box_intersection_d/test/Box_intersection_d/CMakeLists.txt @@ -1,27 +1,22 @@ # Created by the script cgal_create_cmake_script # This is the CMake script for compiling a CGAL application. - cmake_minimum_required(VERSION 3.1...3.15) -project( Box_intersection_d_Tests ) +project(Box_intersection_d_Tests) -find_package( CGAL QUIET ) +find_package(CGAL REQUIRED) -find_package( TBB ) +find_package(TBB) include(CGAL_TBB_support) -if ( CGAL_FOUND ) +create_single_source_cgal_program("automated_test.cpp") +create_single_source_cgal_program("benchmark_box_intersection.cpp") +create_single_source_cgal_program("random_set_test.cpp") +create_single_source_cgal_program("test_box_grid.cpp") - create_single_source_cgal_program( "automated_test.cpp" ) - create_single_source_cgal_program( "benchmark_box_intersection.cpp" ) - create_single_source_cgal_program( "random_set_test.cpp" ) - create_single_source_cgal_program( "test_box_grid.cpp" ) - - if(TARGET CGAL::TBB_support) - target_link_libraries(test_box_grid PUBLIC CGAL::TBB_support) - else() - message( STATUS "NOTICE: Intel TBB was not found. Sequential code will be used." ) - endif() +if(TARGET CGAL::TBB_support) + target_link_libraries(test_box_grid PUBLIC CGAL::TBB_support) else() - message(STATUS "This program requires the CGAL library, and will not be compiled.") + message( + STATUS "NOTICE: Intel TBB was not found. Sequential code will be used.") endif() diff --git a/CGAL_Core/examples/Core/CMakeLists.txt b/CGAL_Core/examples/Core/CMakeLists.txt index 1ff71a69b29..96bf8fcbfde 100644 --- a/CGAL_Core/examples/Core/CMakeLists.txt +++ b/CGAL_Core/examples/Core/CMakeLists.txt @@ -1,26 +1,25 @@ cmake_minimum_required(VERSION 3.1...3.15) -project( Core_Examples ) - - - - +project(Core_Examples) # CGAL and its components -find_package( CGAL QUIET COMPONENTS Core ) +find_package(CGAL REQUIRED COMPONENTS Core) -if ( NOT CGAL_Core_FOUND ) +if(NOT CGAL_Core_FOUND) - message(STATUS "This project requires the CGAL_Core library, and will not be compiled.") + message( + STATUS + "This project requires the CGAL_Core library, and will not be compiled.") return() endif() # Boost and its components -find_package( Boost ) +find_package(Boost) -if ( NOT Boost_FOUND ) +if(NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") + message( + STATUS "This project requires the Boost library, and will not be compiled.") return() @@ -34,4 +33,4 @@ include(${CGAL_USE_FILE}) # Creating entries for all .cpp/.C files with "main" routine # ########################################################## -create_single_source_cgal_program( "delaunay.cpp" ) +create_single_source_cgal_program("delaunay.cpp") diff --git a/CGAL_ImageIO/archive/demo/CGALimageIO/CMakeLists.txt b/CGAL_ImageIO/archive/demo/CGALimageIO/CMakeLists.txt index cebf419d28a..08e42e919b7 100644 --- a/CGAL_ImageIO/archive/demo/CGALimageIO/CMakeLists.txt +++ b/CGAL_ImageIO/archive/demo/CGALimageIO/CMakeLists.txt @@ -6,24 +6,21 @@ if(NOT POLICY CMP0070 AND POLICY CMP0053) cmake_policy(SET CMP0053 OLD) endif() - set(PACKAGE_ROOT ../..) # Add several CGAL packages to the include and link paths, # if they lie in ${PACKAGE_ROOT}/. -foreach(INC_DIR ${PACKAGE_ROOT}/include - ${PACKAGE_ROOT}/../CGAL_ImageIO/include ) +foreach(INC_DIR ${PACKAGE_ROOT}/include ${PACKAGE_ROOT}/../CGAL_ImageIO/include) if(EXISTS ${INC_DIR}) - include_directories (BEFORE ${INC_DIR}) + include_directories(BEFORE ${INC_DIR}) endif() endforeach() foreach(LIB_DIR ${PACKAGE_ROOT}/../CGAL_ImageIO/src/CGAL_ImageIO) - if (EXISTS ${LIB_DIR}) - link_directories (${LIB_DIR}) + if(EXISTS ${LIB_DIR}) + link_directories(${LIB_DIR}) endif() endforeach() - find_package(CGAL REQUIRED ImageIO) find_package(VTK QUIET NO_MODULE) @@ -35,19 +32,24 @@ if(VTK_FOUND) include(${VTK_USE_FILE}) find_package(Qt${VTK_QT_VERSION} COMPONENTS QtGui) if(NOT TARGET Qt${VTK_QT_VERSION}::QtGui) - message(STATUS "NOTICE: vtkRenderingQt needs Qt${VTK_QT_VERSION}, and will not be compiled.") + message( + STATUS + "NOTICE: vtkRenderingQt needs Qt${VTK_QT_VERSION}, and will not be compiled." + ) return() endif() - add_executable( image_to_vtk_viewer image_to_vtk_viewer.cpp ) - add_to_cached_list( CGAL_EXECUTABLE_TARGETS image_to_vtk_viewer ) + add_executable(image_to_vtk_viewer image_to_vtk_viewer.cpp) + add_to_cached_list(CGAL_EXECUTABLE_TARGETS image_to_vtk_viewer) - target_link_libraries( image_to_vtk_viewer - ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} - ${VTK_LIBRARIES} Qt${VTK_QT_VERSION}::QtGui - ) + target_link_libraries( + image_to_vtk_viewer ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} + ${VTK_LIBRARIES} Qt${VTK_QT_VERSION}::QtGui) else() - message(STATUS "NOTICE: This demo needs vtkRenderingQt and vtkFiltersModeling, and will not be compiled.") + message( + STATUS + "NOTICE: This demo needs vtkRenderingQt and vtkFiltersModeling, and will not be compiled." + ) endif() else() message(STATUS "NOTICE: This demo needs VTK, and will not be compiled.") diff --git a/CGAL_ImageIO/examples/CGALimageIO/CMakeLists.txt b/CGAL_ImageIO/examples/CGALimageIO/CMakeLists.txt index 06327048deb..388320a6938 100644 --- a/CGAL_ImageIO/examples/CGALimageIO/CMakeLists.txt +++ b/CGAL_ImageIO/examples/CGALimageIO/CMakeLists.txt @@ -2,21 +2,23 @@ # This is the CMake script for compiling a CGAL application. cmake_minimum_required(VERSION 3.1...3.15) -project( CGALimageIO_Examples ) - +project(CGALimageIO_Examples) if(POLICY CMP0074) cmake_policy(SET CMP0074 NEW) endif() -find_package(CGAL QUIET COMPONENTS ImageIO ) +find_package(CGAL REQUIRED COMPONENTS ImageIO) if(CGAL_ImageIO_FOUND) include(${CGAL_USE_FILE}) - create_single_source_cgal_program( "convert_raw_image_to_inr.cpp" ) - create_single_source_cgal_program( "test_imageio.cpp" ) - create_single_source_cgal_program( "extract_a_sub_image.cpp" ) + create_single_source_cgal_program("convert_raw_image_to_inr.cpp") + create_single_source_cgal_program("test_imageio.cpp") + create_single_source_cgal_program("extract_a_sub_image.cpp") else() - message(STATUS "NOTICE: This demo needs the CGAL ImageIO library, and will not be compiled.") + message( + STATUS + "NOTICE: This demo needs the CGAL ImageIO library, and will not be compiled." + ) endif() diff --git a/CGAL_ImageIO/include/CGAL/ImageIO/analyze_impl.h b/CGAL_ImageIO/include/CGAL/ImageIO/analyze_impl.h index 1154d6b361a..1c326b6fa1f 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO/analyze_impl.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO/analyze_impl.h @@ -33,17 +33,18 @@ /** Magic header for ANALYZE files written in big endian format */ #define ANALYZE_BE_MAGIC "\134\001\000\000" -#define DT_NONE 0 -#define DT_UNKNOWN 0 /*Unknown data type*/ -#define DT_BINARY 1 /*Binary (1 bit per voxel)*/ -#define DT_UNSIGNED_CHAR 2 /*Unsigned character (8 bits per voxel)*/ -#define DT_SIGNED_SHORT 4 /*Signed short (16 bits per voxel)*/ -#define DT_SIGNED_INT 8 /*Signed integer (32 bits per voxel)*/ -#define DT_FLOAT 16 /*Floating point (32 bits per voxel)*/ -#define DT_COMPLEX 32 /*Complex (64 bits per voxel; 2 floating point numbers) */ -#define DT_DOUBLE 64 /*Double precision (64 bits per voxel)*/ -#define DT_RGB 128 /* */ -#define DT_ALL 255 /* */ +//use prefix CGAL_analyze_impl_ to avoid clashing and breaking dirent.h +#define CGAL_analyze_impl_DT_NONE 0 +#define CGAL_analyze_impl_DT_UNKNOWN 0 /*Unknown data type*/ +#define CGAL_analyze_impl_DT_BINARY 1 /*Binary (1 bit per voxel)*/ +#define CGAL_analyze_impl_DT_UNSIGNED_CHAR 2 /*Unsigned character (8 bits per voxel)*/ +#define CGAL_analyze_impl_DT_SIGNED_SHORT 4 /*Signed short (16 bits per voxel)*/ +#define CGAL_analyze_impl_DT_SIGNED_INT 8 /*Signed integer (32 bits per voxel)*/ +#define CGAL_analyze_impl_DT_FLOAT 16 /*Floating point (32 bits per voxel)*/ +#define CGAL_analyze_impl_DT_COMPLEX 32 /*Complex (64 bits per voxel; 2 floating point numbers) */ +#define CGAL_analyze_impl_DT_DOUBLE 64 /*Double precision (64 bits per voxel)*/ +#define CGAL_analyze_impl_DT_RGB 128 /* */ +#define CGAL_analyze_impl_DT_ALL 255 /* */ #include @@ -373,17 +374,17 @@ int _readAnalyzeHeader( _image* im, const char* name, switch(analyzeHeader->dime.datatype) { - case DT_BINARY: - case DT_UNSIGNED_CHAR: - case DT_SIGNED_SHORT: - case DT_SIGNED_INT: - case DT_FLOAT: - case DT_COMPLEX: - case DT_DOUBLE: + case CGAL_analyze_impl_DT_BINARY: + case CGAL_analyze_impl_DT_UNSIGNED_CHAR: + case CGAL_analyze_impl_DT_SIGNED_SHORT: + case CGAL_analyze_impl_DT_SIGNED_INT: + case CGAL_analyze_impl_DT_FLOAT: + case CGAL_analyze_impl_DT_COMPLEX: + case CGAL_analyze_impl_DT_DOUBLE: im->vdim = 1; break ; - case DT_RGB: + case CGAL_analyze_impl_DT_RGB: im->vdim = 3; break ; @@ -396,17 +397,17 @@ int _readAnalyzeHeader( _image* im, const char* name, switch(analyzeHeader->dime.datatype) { - case DT_BINARY: - case DT_UNSIGNED_CHAR: - case DT_SIGNED_SHORT: - case DT_SIGNED_INT: - case DT_RGB: + case CGAL_analyze_impl_DT_BINARY: + case CGAL_analyze_impl_DT_UNSIGNED_CHAR: + case CGAL_analyze_impl_DT_SIGNED_SHORT: + case CGAL_analyze_impl_DT_SIGNED_INT: + case CGAL_analyze_impl_DT_RGB: im->wordKind = WK_FIXED; break ; - case DT_FLOAT: - case DT_COMPLEX: - case DT_DOUBLE: + case CGAL_analyze_impl_DT_FLOAT: + case CGAL_analyze_impl_DT_COMPLEX: + case CGAL_analyze_impl_DT_DOUBLE: im->wordKind = WK_FLOAT; break ; @@ -419,17 +420,17 @@ int _readAnalyzeHeader( _image* im, const char* name, switch(analyzeHeader->dime.datatype) { - case DT_BINARY: - case DT_UNSIGNED_CHAR: - case DT_RGB: + case CGAL_analyze_impl_DT_BINARY: + case CGAL_analyze_impl_DT_UNSIGNED_CHAR: + case CGAL_analyze_impl_DT_RGB: im->sign = SGN_UNSIGNED; break ; - case DT_SIGNED_SHORT: - case DT_SIGNED_INT: - case DT_FLOAT: - case DT_COMPLEX: - case DT_DOUBLE: + case CGAL_analyze_impl_DT_SIGNED_SHORT: + case CGAL_analyze_impl_DT_SIGNED_INT: + case CGAL_analyze_impl_DT_FLOAT: + case CGAL_analyze_impl_DT_COMPLEX: + case CGAL_analyze_impl_DT_DOUBLE: im->sign = SGN_SIGNED; break ; @@ -441,7 +442,7 @@ int _readAnalyzeHeader( _image* im, const char* name, } im->wdim = analyzeHeader->dime.bitpix; - if( analyzeHeader->dime.datatype == DT_RGB ) + if( analyzeHeader->dime.datatype == CGAL_analyze_impl_DT_RGB ) { im->wdim /= 3 ; } @@ -612,10 +613,10 @@ writeAnalyzeHeader( const _image* im ) if( im->wdim == 1 ) { if ( im->vdim == 1 ) { - hdr.dime.datatype = DT_UNSIGNED_CHAR ; + hdr.dime.datatype = CGAL_analyze_impl_DT_UNSIGNED_CHAR ; } else if ( im->vdim == 3 ) { - hdr.dime.datatype = DT_RGB ; + hdr.dime.datatype = CGAL_analyze_impl_DT_RGB ; } else { fprintf( stderr, "%s: unsupported image type\n", proc ); @@ -643,7 +644,7 @@ writeAnalyzeHeader( const _image* im ) if ( imin > *buf ) imin = *buf; } if ( imax < 32768 ) { - hdr.dime.datatype = DT_SIGNED_SHORT ; + hdr.dime.datatype = CGAL_analyze_impl_DT_SIGNED_SHORT ; } else { fprintf( stderr, "%s: conversion from unsigned short to short impossible, max=%d\n", proc, imax ); @@ -676,7 +677,7 @@ writeAnalyzeHeader( const _image* im ) if ( imax < *buf ) imax = *buf; if ( imin > *buf ) imin = *buf; } - hdr.dime.datatype = DT_SIGNED_SHORT ; + hdr.dime.datatype = CGAL_analyze_impl_DT_SIGNED_SHORT ; } else if( im->wdim == 4 ) { int *buf = (int*)im->data; @@ -686,7 +687,7 @@ writeAnalyzeHeader( const _image* im ) if ( imax < *buf ) imax = *buf; if ( imin > *buf ) imin = *buf; } - hdr.dime.datatype = DT_SIGNED_INT ; + hdr.dime.datatype = CGAL_analyze_impl_DT_SIGNED_INT ; } else { fprintf( stderr, "%s: unsupported image type\n", proc ); @@ -699,10 +700,10 @@ writeAnalyzeHeader( const _image* im ) return -1; } if( im->wdim == 4 ) { - hdr.dime.datatype = DT_FLOAT ; + hdr.dime.datatype = CGAL_analyze_impl_DT_FLOAT ; } else if( im->wdim == 8 ) { - hdr.dime.datatype = DT_DOUBLE ; + hdr.dime.datatype = CGAL_analyze_impl_DT_DOUBLE ; } else { fprintf( stderr, "%s: unsupported image type\n", proc ); diff --git a/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h b/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h index 61cdcd701b3..119b6e2d515 100644 --- a/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h +++ b/CGAL_ImageIO/include/CGAL/ImageIO/gif_impl.h @@ -60,7 +60,7 @@ typedef unsigned char byte; #define COLORMAPMASK 0x80 -#define DEBUG 0 +#define CGAL_GIF_IMPL_DEBUG 0 //FILE *fp; //int gif89 = 0; @@ -219,7 +219,7 @@ int gif89 = 0; if (aspect) { if (!gif89) return(GifError("corrupt GIF file (screen descriptor)")); else normaspect = (float) (aspect + 15) / 64.0f; /* gif89 aspect ratio */ - if (DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect); + if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF89 aspect = %f\n", normaspect); } @@ -268,7 +268,7 @@ int gif89 = 0; /* read extension block */ fn = NEXTBYTE; - if (DEBUG) fprintf(stderr,"GIF extension type 0x%02x\n", fn); + if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF extension type 0x%02x\n", fn); if (fn == 'R') { /* GIF87 aspect extension */ blocksize = NEXTBYTE; @@ -279,7 +279,7 @@ int gif89 = 0; normaspect = (float) aspnum / (float) aspden; else { normaspect = 1.0; aspnum = aspden = 1; } - if (DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n\n", + if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"GIF87 aspect extension: %d:%d = %f\n\n", aspnum, aspden,normaspect); } else { @@ -290,16 +290,16 @@ int gif89 = 0; else if (fn == 0xFE) { /* Comment Extension. just eat it */ int ch, j, sbsize; - if (DEBUG) fprintf(stderr,"Comment extension: "); + if (CGAL_GIF_IMPL_DEBUG) fprintf(stderr,"Comment extension: "); /* read (and ignore) data sub-blocks */ do { j = 0; sbsize = NEXTBYTE; while (j #include #include +#include #include -typedef CGAL::Parallel_if_available_tag Concurrency_tag; - typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; typedef Kernel::Iso_cuboid_3 Iso_cuboid_3; @@ -84,9 +83,7 @@ int main (int argc, char** argv) std::cerr << "Computing features" << std::endl; Feature_set features; -#ifdef CGAL_LINKED_WITH_TBB - features.begin_parallel_additions(); -#endif + features.begin_parallel_additions(); // No effect in sequential mode Feature_handle distance_to_plane = features.add (pts, Pmap(), eigen); Feature_handle dispersion = features.add (pts, Pmap(), grid, @@ -94,9 +91,7 @@ int main (int argc, char** argv) Feature_handle elevation = features.add (pts, Pmap(), grid, radius_dtm); -#ifdef CGAL_LINKED_WITH_TBB - features.end_parallel_additions(); -#endif + features.end_parallel_additions(); // No effect in sequential mode //! [Features] /////////////////////////////////////////////////////////////////// @@ -105,9 +100,15 @@ int main (int argc, char** argv) //! [Labels] Label_set labels; + + // Init name only Label_handle ground = labels.add ("ground"); - Label_handle vegetation = labels.add ("vegetation"); - Label_handle roof = labels.add ("roof"); + + // Init name and color + Label_handle vegetation = labels.add ("vegetation", CGAL::Color(0,255,0)); + + // Init name, Color and standard index (here, ASPRS building index) + Label_handle roof = labels.add ("roof", CGAL::Color (255, 0, 0), 6); //! [Labels] /////////////////////////////////////////////////////////////////// @@ -146,7 +147,7 @@ int main (int argc, char** argv) CGAL::Real_timer t; t.start(); - Classification::classify (pts, labels, classifier, label_indices); + Classification::classify (pts, labels, classifier, label_indices); t.stop(); std::cerr << "Raw classification performed in " << t.time() << " second(s)" << std::endl; t.reset(); @@ -156,7 +157,7 @@ int main (int argc, char** argv) /////////////////////////////////////////////////////////////////// //! [Smoothing] t.start(); - Classification::classify_with_local_smoothing + Classification::classify_with_local_smoothing (pts, Pmap(), labels, classifier, neighborhood.sphere_neighbor_query(radius_neighbors), label_indices); @@ -169,7 +170,7 @@ int main (int argc, char** argv) /////////////////////////////////////////////////////////////////// //! [Graph_cut] t.start(); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (pts, Pmap(), labels, classifier, neighborhood.k_neighbor_query(12), 0.2f, 4, label_indices); @@ -180,36 +181,43 @@ int main (int argc, char** argv) // Save the output in a colored PLY format - std::ofstream f ("classification.ply"); - f << "ply" << std::endl - << "format ascii 1.0" << std::endl - << "element vertex " << pts.size() << std::endl - << "property float x" << std::endl - << "property float y" << std::endl - << "property float z" << std::endl - << "property uchar red" << std::endl - << "property uchar green" << std::endl - << "property uchar blue" << std::endl - << "end_header" << std::endl; + std::vector red, green, blue; + red.reserve(pts.size()); + green.reserve(pts.size()); + blue.reserve(pts.size()); for (std::size_t i = 0; i < pts.size(); ++ i) { - f << pts[i] << " "; - Label_handle label = labels[std::size_t(label_indices[i])]; + unsigned r = 0, g = 0, b = 0; if (label == ground) - f << "245 180 0" << std::endl; - else if (label == vegetation) - f << "0 255 27" << std::endl; - else if (label == roof) - f << "255 0 170" << std::endl; - else { - f << "0 0 0" << std::endl; - std::cerr << "Error: unknown classification label" << std::endl; + r = 245; g = 180; b = 0; } + else if (label == vegetation) + { + r = 0; g = 255; b = 27; + } + else if (label == roof) + { + r = 255; g = 0; b = 170; + } + red.push_back(r); + green.push_back(g); + blue.push_back(b); } + std::ofstream f ("classification.ply"); + + CGAL::write_ply_points_with_properties + (f, CGAL::make_range (boost::counting_iterator(0), + boost::counting_iterator(pts.size())), + CGAL::make_ply_point_writer (CGAL::make_property_map(pts)), + std::make_pair(CGAL::make_property_map(red), CGAL::PLY_property("red")), + std::make_pair(CGAL::make_property_map(green), CGAL::PLY_property("green")), + std::make_pair(CGAL::make_property_map(blue), CGAL::PLY_property("blue"))); + + std::cerr << "All done" << std::endl; return EXIT_SUCCESS; } diff --git a/Classification/examples/Classification/example_cluster_classification.cpp b/Classification/examples/Classification/example_cluster_classification.cpp index 3c4b08f60e6..1573a0fc1ad 100644 --- a/Classification/examples/Classification/example_cluster_classification.cpp +++ b/Classification/examples/Classification/example_cluster_classification.cpp @@ -18,8 +18,6 @@ #include #include -typedef CGAL::Parallel_if_available_tag Concurrency_tag; - typedef CGAL::Simple_cartesian Kernel; typedef Kernel::Point_3 Point; typedef Kernel::Iso_cuboid_3 Iso_cuboid_3; @@ -37,6 +35,7 @@ typedef CGAL::Shape_detection::Point_set::Least_squares_plane_fit_region Region_growing; namespace Classification = CGAL::Classification; +namespace Feature = CGAL::Classification::Feature; typedef Classification::Label_handle Label_handle; typedef Classification::Feature_handle Feature_handle; @@ -50,7 +49,7 @@ typedef Classification::Cluster Clu int main (int argc, char** argv) { std::string filename = "data/b9.ply"; - std::string filename_config = "data/b9_clusters_config.gz"; + std::string filename_config = "data/b9_clusters_config.bin"; if (argc > 1) filename = argv[1]; @@ -67,7 +66,7 @@ int main (int argc, char** argv) CGAL::Real_timer t; t.start(); pts.add_normal_map(); - CGAL::jet_estimate_normals (pts, 12); + CGAL::jet_estimate_normals (pts, 12); t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; t.reset(); @@ -151,50 +150,38 @@ int main (int argc, char** argv) Feature_set features; -#ifdef CGAL_LINKED_WITH_TBB - features.begin_parallel_additions(); -#endif - // First, compute means of features. - for (std::size_t i = 0; i < pointwise_features.size(); ++ i) - features.add (clusters, pointwise_features[i]); - -#ifdef CGAL_LINKED_WITH_TBB - features.end_parallel_additions(); features.begin_parallel_additions(); -#endif + for (Feature_handle fh : pointwise_features) + features.add (clusters, fh); + features.end_parallel_additions(); // Then, compute variances of features (and remaining cluster features). + features.begin_parallel_additions(); for (std::size_t i = 0; i < pointwise_features.size(); ++ i) - features.add (clusters, - pointwise_features[i], // i^th feature - features[i]); // mean of i^th feature + features.add (clusters, + pointwise_features[i], // i^th feature + features[i]); // mean of i^th feature - features.add (clusters); - features.add (clusters); + features.add (clusters); + features.add (clusters); for (std::size_t i = 0; i < 3; ++ i) - features.add (clusters, eigen, (unsigned int)(i)); + features.add (clusters, eigen, (unsigned int)(i)); -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif //! [Features] /////////////////////////////////////////////////////////////////// t.stop(); - // Add types. - Label_set labels; - Label_handle ground = labels.add ("ground"); - Label_handle vegetation = labels.add ("vegetation"); - Label_handle roof = labels.add ("roof"); + Label_set labels = { "ground", "vegetation", "roof" }; std::vector label_indices(clusters.size(), -1); std::cerr << "Using ETHZ Random Forest Classifier" << std::endl; - Classification::ETHZ_random_forest_classifier classifier (labels, features); + Classification::ETHZ::Random_forest_classifier classifier (labels, features); std::cerr << "Loading configuration" << std::endl; std::ifstream in_config (filename_config, std::ios_base::in | std::ios_base::binary); @@ -203,7 +190,7 @@ int main (int argc, char** argv) std::cerr << "Classifying" << std::endl; t.reset(); t.start(); - Classification::classify (clusters, labels, classifier, label_indices); + Classification::classify (clusters, labels, classifier, label_indices); t.stop(); std::cerr << "Classification done in " << t.time() << " second(s)" << std::endl; diff --git a/Classification/examples/Classification/example_deprecated_conversion.cpp b/Classification/examples/Classification/example_deprecated_conversion.cpp new file mode 100644 index 00000000000..d63080d93af --- /dev/null +++ b/Classification/examples/Classification/example_deprecated_conversion.cpp @@ -0,0 +1,20 @@ +#include + +#include +#include + +int main (int argc, char** argv) +{ + if (argc != 3) + std::cerr << "Usage: " << argv[0] << " input.gz output.bin" << std::endl; + else + { + std::ifstream ifile (argv[1], std::ios_base::binary); + std::ofstream ofile (argv[2], std::ios_base::binary); + + CGAL::Classification::ETHZ::Random_forest_classifier:: + convert_deprecated_configuration_to_new_format(ifile, ofile); + } + + return EXIT_SUCCESS; +} diff --git a/Classification/examples/Classification/example_ethz_random_forest.cpp b/Classification/examples/Classification/example_ethz_random_forest.cpp index bfacdd4e047..b0333f58ec4 100644 --- a/Classification/examples/Classification/example_ethz_random_forest.cpp +++ b/Classification/examples/Classification/example_ethz_random_forest.cpp @@ -49,18 +49,13 @@ int main (int argc, char** argv) Imap label_map; bool lm_found = false; - boost::tie (label_map, lm_found) = pts.property_map ("label"); + std::tie (label_map, lm_found) = pts.property_map ("label"); if (!lm_found) { std::cerr << "Error: \"label\" property not found in input file." << std::endl; return EXIT_FAILURE; } - std::vector ground_truth; - ground_truth.reserve (pts.size()); - std::copy (pts.range(label_map).begin(), pts.range(label_map).end(), - std::back_inserter (ground_truth)); - Feature_set features; std::cerr << "Generating features" << std::endl; @@ -69,25 +64,23 @@ int main (int argc, char** argv) Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales -#ifdef CGAL_LINKED_WITH_TBB features.begin_parallel_additions(); -#endif - generator.generate_point_based_features (features); - -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; - // Add types + // Add labels Label_set labels; Label_handle ground = labels.add ("ground"); Label_handle vegetation = labels.add ("vegetation"); Label_handle roof = labels.add ("roof"); + // Check if ground truth is valid for this label set + if (!labels.is_valid_ground_truth (pts.range(label_map), true)) + return EXIT_FAILURE; + std::vector label_indices(pts.size(), -1); std::cerr << "Using ETHZ Random Forest Classifier" << std::endl; @@ -96,13 +89,13 @@ int main (int argc, char** argv) std::cerr << "Training" << std::endl; t.reset(); t.start(); - classifier.train (ground_truth); + classifier.train (pts.range(label_map)); t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; t.reset(); t.start(); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (pts, pts.point_map(), labels, classifier, generator.neighborhood().k_neighbor_query(12), 0.2f, 1, label_indices); @@ -111,15 +104,15 @@ int main (int argc, char** argv) std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; - Classification::Evaluation evaluation (labels, ground_truth, label_indices); + Classification::Evaluation evaluation (labels, pts.range(label_map), label_indices); - for (std::size_t i = 0; i < labels.size(); ++ i) + for (Label_handle l : labels) { - std::cerr << " * " << labels[i]->name() << ": " - << evaluation.precision(labels[i]) << " ; " - << evaluation.recall(labels[i]) << " ; " - << evaluation.f1_score(labels[i]) << " ; " - << evaluation.intersection_over_union(labels[i]) << std::endl; + std::cerr << " * " << l->name() << ": " + << evaluation.precision(l) << " ; " + << evaluation.recall(l) << " ; " + << evaluation.f1_score(l) << " ; " + << evaluation.intersection_over_union(l) << std::endl; } std::cerr << "Accuracy = " << evaluation.accuracy() << std::endl @@ -136,21 +129,16 @@ int main (int argc, char** argv) label_map[i] = label_indices[i]; // update label map with computed classification Label_handle label = labels[label_indices[i]]; - - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } + // Save configuration for later use + std::ofstream fconfig ("ethz_random_forest.bin", std::ios_base::binary); + classifier.save_configuration(fconfig); + // Write result std::ofstream f ("classification.ply"); f.precision(18); diff --git a/Classification/examples/Classification/example_feature.cpp b/Classification/examples/Classification/example_feature.cpp index 4f77c18d941..68128ba08e8 100644 --- a/Classification/examples/Classification/example_feature.cpp +++ b/Classification/examples/Classification/example_feature.cpp @@ -115,7 +115,7 @@ int main (int argc, char** argv) std::cerr << "Classifying" << std::endl; std::vector label_indices(pts.size(), -1); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (pts, Pmap(), labels, classifier, neighborhood.k_neighbor_query(12), 0.5, 1, label_indices); diff --git a/Classification/examples/Classification/example_generation_and_training.cpp b/Classification/examples/Classification/example_generation_and_training.cpp index 2a34076ef77..cb911262b32 100644 --- a/Classification/examples/Classification/example_generation_and_training.cpp +++ b/Classification/examples/Classification/example_generation_and_training.cpp @@ -46,18 +46,13 @@ int main (int argc, char** argv) Imap label_map; bool lm_found = false; - boost::tie (label_map, lm_found) = pts.property_map ("label"); + std::tie (label_map, lm_found) = pts.property_map ("label"); if (!lm_found) { std::cerr << "Error: \"label\" property not found in input file." << std::endl; return EXIT_FAILURE; } - std::vector ground_truth; - ground_truth.reserve (pts.size()); - std::copy (pts.range(label_map).begin(), pts.range(label_map).end(), - std::back_inserter (ground_truth)); - std::cerr << "Generating features" << std::endl; CGAL::Real_timer t; t.start(); @@ -70,15 +65,9 @@ int main (int argc, char** argv) std::size_t number_of_scales = 5; Feature_generator generator (pts, pts.point_map(), number_of_scales); -#ifdef CGAL_LINKED_WITH_TBB features.begin_parallel_additions(); -#endif - generator.generate_point_based_features (features); - -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif //! [Generator] /////////////////////////////////////////////////////////////////// @@ -86,25 +75,21 @@ int main (int argc, char** argv) t.stop(); std::cerr << features.size() << " feature(s) generated in " << t.time() << " second(s)" << std::endl; - // Add types - Label_set labels; - Label_handle ground = labels.add ("ground"); - Label_handle vegetation = labels.add ("vegetation"); - Label_handle roof = labels.add ("roof"); + Label_set labels = { "ground", "vegetation", "roof" }; Classifier classifier (labels, features); std::cerr << "Training" << std::endl; t.reset(); t.start(); - classifier.train (ground_truth, 800); + classifier.train (pts.range(label_map), 800); t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; t.reset(); t.start(); std::vector label_indices(pts.size(), -1); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (pts, pts.point_map(), labels, classifier, generator.neighborhood().k_neighbor_query(12), 0.2f, 10, label_indices); @@ -112,15 +97,15 @@ int main (int argc, char** argv) std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; - Classification::Evaluation evaluation (labels, ground_truth, label_indices); + Classification::Evaluation evaluation (labels, pts.range(label_map), label_indices); - for (std::size_t i = 0; i < labels.size(); ++ i) + for (Label_handle l : labels) { - std::cerr << " * " << labels[i]->name() << ": " - << evaluation.precision(labels[i]) << " ; " - << evaluation.recall(labels[i]) << " ; " - << evaluation.f1_score(labels[i]) << " ; " - << evaluation.intersection_over_union(labels[i]) << std::endl; + std::cerr << " * " << l->name() << ": " + << evaluation.precision(l) << " ; " + << evaluation.recall(l) << " ; " + << evaluation.f1_score(l) << " ; " + << evaluation.intersection_over_union(l) << std::endl; } std::cerr << "Accuracy = " << evaluation.accuracy() << std::endl diff --git a/Classification/examples/Classification/example_mesh_classification.cpp b/Classification/examples/Classification/example_mesh_classification.cpp index 465b3a4bfcd..1d081e869fa 100644 --- a/Classification/examples/Classification/example_mesh_classification.cpp +++ b/Classification/examples/Classification/example_mesh_classification.cpp @@ -32,7 +32,7 @@ typedef Classification::Mesh_feature_generator int main (int argc, char** argv) { std::string filename = "data/b9_mesh.off"; - std::string filename_config = "data/b9_mesh_config.gz"; + std::string filename_config = "data/b9_mesh_config.bin"; if (argc > 1) filename = argv[1]; @@ -59,16 +59,10 @@ int main (int argc, char** argv) std::size_t number_of_scales = 5; Feature_generator generator (mesh, face_point_map, number_of_scales); -#ifdef CGAL_LINKED_WITH_TBB features.begin_parallel_additions(); -#endif - generator.generate_point_based_features (features); // Features that consider the mesh as a point set generator.generate_face_based_features (features); // Features computed directly on mesh faces - -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif //! [Generator] /////////////////////////////////////////////////////////////////// @@ -76,11 +70,7 @@ int main (int argc, char** argv) t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; - // Add types - Label_set labels; - Label_handle ground = labels.add ("ground"); - Label_handle vegetation = labels.add ("vegetation"); - Label_handle roof = labels.add ("roof"); + Label_set labels = { "ground", "vegetation", "roof" }; std::vector label_indices(mesh.number_of_faces(), -1); @@ -94,7 +84,7 @@ int main (int argc, char** argv) std::cerr << "Classifying with graphcut" << std::endl; t.reset(); t.start(); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (mesh.faces(), Face_with_bbox_map(&mesh), labels, classifier, generator.neighborhood().n_ring_neighbor_query(2), 0.2f, 1, label_indices); diff --git a/Classification/examples/Classification/example_opencv_random_forest.cpp b/Classification/examples/Classification/example_opencv_random_forest.cpp index e0cd90e51f0..2491e05d0a7 100644 --- a/Classification/examples/Classification/example_opencv_random_forest.cpp +++ b/Classification/examples/Classification/example_opencv_random_forest.cpp @@ -49,18 +49,13 @@ int main (int argc, char** argv) Imap label_map; bool lm_found = false; - boost::tie (label_map, lm_found) = pts.property_map ("label"); + std::tie (label_map, lm_found) = pts.property_map ("label"); if (!lm_found) { std::cerr << "Error: \"label\" property not found in input file." << std::endl; return EXIT_FAILURE; } - std::vector ground_truth; - ground_truth.reserve (pts.size()); - std::copy (pts.range(label_map).begin(), pts.range(label_map).end(), - std::back_inserter (ground_truth)); - Feature_set features; std::cerr << "Generating features" << std::endl; @@ -69,19 +64,14 @@ int main (int argc, char** argv) Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales -#ifdef CGAL_LINKED_WITH_TBB features.begin_parallel_additions(); -#endif - generator.generate_point_based_features (features); -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; - // Add types + // Add labels Label_set labels; Label_handle ground = labels.add ("ground"); Label_handle vegetation = labels.add ("vegetation"); @@ -95,13 +85,13 @@ int main (int argc, char** argv) std::cerr << "Training" << std::endl; t.reset(); t.start(); - classifier.train (ground_truth); + classifier.train (pts.range(label_map)); t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; t.reset(); t.start(); - Classification::classify_with_graphcut + Classification::classify_with_graphcut (pts, pts.point_map(), labels, classifier, generator.neighborhood().k_neighbor_query(12), 0.2f, 1, label_indices); @@ -110,15 +100,15 @@ int main (int argc, char** argv) std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; - Classification::Evaluation evaluation (labels, ground_truth, label_indices); + Classification::Evaluation evaluation (labels, pts.range(label_map), label_indices); - for (std::size_t i = 0; i < labels.size(); ++ i) + for (Label_handle l : labels) { - std::cerr << " * " << labels[i]->name() << ": " - << evaluation.precision(labels[i]) << " ; " - << evaluation.recall(labels[i]) << " ; " - << evaluation.f1_score(labels[i]) << " ; " - << evaluation.intersection_over_union(labels[i]) << std::endl; + std::cerr << " * " << l->name() << ": " + << evaluation.precision(l) << " ; " + << evaluation.recall(l) << " ; " + << evaluation.f1_score(l) << " ; " + << evaluation.intersection_over_union(l) << std::endl; } std::cerr << "Accuracy = " << evaluation.accuracy() << std::endl @@ -135,19 +125,10 @@ int main (int argc, char** argv) label_map[i] = label_indices[i]; // update label map with computed classification Label_handle label = labels[label_indices[i]]; - - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } // Write result diff --git a/Classification/examples/Classification/example_tensorflow_neural_network.cpp b/Classification/examples/Classification/example_tensorflow_neural_network.cpp index 01fd4f1cac2..6a454360285 100644 --- a/Classification/examples/Classification/example_tensorflow_neural_network.cpp +++ b/Classification/examples/Classification/example_tensorflow_neural_network.cpp @@ -49,18 +49,13 @@ int main (int argc, char** argv) Imap label_map; bool lm_found = false; - boost::tie (label_map, lm_found) = pts.property_map ("label"); + std::tie (label_map, lm_found) = pts.property_map ("label"); if (!lm_found) { std::cerr << "Error: \"label\" property not found in input file." << std::endl; return EXIT_FAILURE; } - std::vector ground_truth; - ground_truth.reserve (pts.size()); - std::copy (pts.range(label_map).begin(), pts.range(label_map).end(), - std::back_inserter (ground_truth)); - Feature_set features; std::cerr << "Generating features" << std::endl; @@ -69,20 +64,14 @@ int main (int argc, char** argv) Feature_generator generator (pts, pts.point_map(), 5); // using 5 scales -#ifdef CGAL_LINKED_WITH_TBB features.begin_parallel_additions(); -#endif - generator.generate_point_based_features (features); - -#ifdef CGAL_LINKED_WITH_TBB features.end_parallel_additions(); -#endif t.stop(); std::cerr << "Done in " << t.time() << " second(s)" << std::endl; - // Add types + // Add labels Label_set labels; Label_handle ground = labels.add ("ground"); Label_handle vegetation = labels.add ("vegetation"); @@ -96,7 +85,7 @@ int main (int argc, char** argv) std::cerr << "Training" << std::endl; t.reset(); t.start(); - classifier.train (ground_truth, + classifier.train (pts.range(ground_truth), true, // restart from scratch 100); // 100 iterations t.stop(); @@ -113,15 +102,15 @@ int main (int argc, char** argv) std::cerr << "Classification with graphcut done in " << t.time() << " second(s)" << std::endl; std::cerr << "Precision, recall, F1 scores and IoU:" << std::endl; - Classification::Evaluation evaluation (labels, ground_truth, label_indices); + Classification::Evaluation evaluation (labels, pts.range(ground_truth), label_indices); - for (std::size_t i = 0; i < labels.size(); ++ i) + for (Label_handle l : labels) { - std::cerr << " * " << labels[i]->name() << ": " - << evaluation.precision(labels[i]) << " ; " - << evaluation.recall(labels[i]) << " ; " - << evaluation.f1_score(labels[i]) << " ; " - << evaluation.intersection_over_union(labels[i]) << std::endl; + std::cerr << " * " << l->name() << ": " + << evaluation.precision(l) << " ; " + << evaluation.recall(l) << " ; " + << evaluation.f1_score(l) << " ; " + << evaluation.intersection_over_union(l) << std::endl; } std::cerr << "Accuracy = " << evaluation.accuracy() << std::endl @@ -138,19 +127,10 @@ int main (int argc, char** argv) label_map[i] = label_indices[i]; // update label map with computed classification Label_handle label = labels[label_indices[i]]; - - if (label == ground) - { - red[i] = 245; green[i] = 180; blue[i] = 0; - } - else if (label == vegetation) - { - red[i] = 0; green[i] = 255; blue[i] = 27; - } - else if (label == roof) - { - red[i] = 255; green[i] = 0; blue[i] = 170; - } + const CGAL::Color& color = label->color(); + red[i] = color.red(); + green[i] = color.green(); + blue[i] = color.blue(); } // Write result diff --git a/Classification/include/CGAL/Classification/Cluster.h b/Classification/include/CGAL/Classification/Cluster.h index 4b8b002c3b5..a0d0f209602 100644 --- a/Classification/include/CGAL/Classification/Cluster.h +++ b/Classification/include/CGAL/Classification/Cluster.h @@ -46,7 +46,7 @@ class Cluster { public: - typedef typename ItemMap::value_type Item; + using Item = typename boost::property_traits::value_type; /// \cond SKIP_IN_MANUAL struct Neighbor_query @@ -64,9 +64,9 @@ public: class Point_idx_to_point_unary_function { public: - typedef std::size_t argument_type; - typedef typename ItemMap::reference result_type; - typedef boost::readable_property_map_tag category; + using argument_type = std::size_t; + using result_type = typename boost::property_traits::reference; + using category = boost::readable_property_map_tag; const ItemRange* m_range; ItemMap m_item_map; @@ -105,9 +105,9 @@ public: \param item_map property map to access the input items. */ Cluster (const ItemRange& range, ItemMap item_map) - : neighbors (new std::vector()) + : neighbors (std::make_shared >()) , m_range (&range), m_item_map (item_map) - , m_inliers (new std::vector()) + , m_inliers (std::make_shared >()) , m_training(-1), m_label(-1) { } diff --git a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h index e2f831b5aca..6b22c41ad00 100644 --- a/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h +++ b/Classification/include/CGAL/Classification/ETHZ/Random_forest_classifier.h @@ -73,7 +73,7 @@ class Random_forest_classifier const Label_set& m_labels; const Feature_set& m_features; - Forest* m_rfc; + std::shared_ptr m_rfc; public: @@ -81,16 +81,16 @@ public: /// @{ /*! - \brief Instantiates the classifier using the sets of `labels` and `features`. + \brief instantiates the classifier using the sets of `labels` and `features`. */ Random_forest_classifier (const Label_set& labels, const Feature_set& features) - : m_labels (labels), m_features (features), m_rfc (nullptr) + : m_labels (labels), m_features (features) { } /*! - \brief Copies the `other` classifier's configuration using another + \brief copies the `other` classifier's configuration using another set of `features`. This constructor can be used to apply a trained random forest to @@ -105,7 +105,7 @@ public: defined(CGAL_LINKED_WITH_BOOST_SERIALIZATION)) Random_forest_classifier (const Random_forest_classifier& other, const Feature_set& features) - : m_labels (other.m_labels), m_features (features), m_rfc (nullptr) + : m_labels (other.m_labels), m_features (features) { std::stringstream stream; other.save_configuration(stream); @@ -113,14 +113,6 @@ public: } #endif - /// \cond SKIP_IN_MANUAL - ~Random_forest_classifier () - { - if (m_rfc != nullptr) - delete m_rfc; - } - /// \endcond - /// @} /// \name Training @@ -138,7 +130,7 @@ public: /// \endcond /*! - \brief Runs the training algorithm. + \brief runs the training algorithm. From the set of provided ground truth, this algorithm estimates sets up the random trees that produce the most accurate result @@ -179,6 +171,8 @@ public: std::size_t num_trees = 25, std::size_t max_depth = 20) { + CGAL_precondition (m_labels.is_valid_ground_truth (ground_truth)); + CGAL::internal::liblearning::RandomForest::ForestParams params; params.n_trees = num_trees; params.max_depth = max_depth; @@ -186,32 +180,40 @@ public: std::vector gt; std::vector ft; - std::size_t idx = 0; - for (const auto& ig : ground_truth) +#ifdef CGAL_CLASSIFICATION_VERBOSE + std::vector count (m_labels.size(), 0); +#endif + + std::size_t i = 0; + for (const auto& gt_value : ground_truth) { - int g = int(ig); + int g = int(gt_value); if (g != -1) { for (std::size_t f = 0; f < m_features.size(); ++ f) - ft.push_back(m_features[f]->value(idx)); + ft.push_back(m_features[f]->value(i)); gt.push_back(g); +#ifdef CGAL_CLASSIFICATION_VERBOSE + count[std::size_t(g)] ++; +#endif } - ++ idx; + ++ i; } - CGAL_CLASSIFICATION_CERR << "Using " << gt.size() << " inliers" << std::endl; + CGAL_CLASSIFICATION_CERR << "Using " << gt.size() << " inliers:" << std::endl; +#ifdef CGAL_CLASSIFICATION_VERBOSE + for (std::size_t i = 0; i < m_labels.size(); ++ i) + std::cerr << " * " << m_labels[i]->name() << ": " << count[i] << " inlier(s)" << std::endl; +#endif CGAL::internal::liblearning::DataView2D label_vector (&(gt[0]), gt.size(), 1); CGAL::internal::liblearning::DataView2D feature_vector(&(ft[0]), gt.size(), ft.size() / gt.size()); - if (m_rfc != nullptr && reset_trees) - { - delete m_rfc; - m_rfc = nullptr; - } + if (m_rfc && reset_trees) + m_rfc.reset(); - if (m_rfc == nullptr) - m_rfc = new Forest (params); + if (!m_rfc) + m_rfc = std::make_shared (params); CGAL::internal::liblearning::RandomForest::AxisAlignedRandomSplitGenerator generator; @@ -245,7 +247,7 @@ public: /// @{ /*! - \brief Computes, for each feature, how many nodes in the forest + \brief computes, for each feature, how many nodes in the forest uses it as a split criterion. Each tree of the random forest recursively splits the training @@ -280,35 +282,37 @@ public: /// @{ /*! - \brief Saves the current configuration in the stream `output`. + \brief saves the current configuration in the stream `output`. This allows to easily save and recover a specific classification configuration. - The output file is written in an GZIP container that is readable - by the `load_configuration()` method. + The output file is written in a binary format that is readable by + the `load_configuration()` method. */ #if defined(DOXYGEN_RUNNING) || \ (defined(CGAL_LINKED_WITH_BOOST_IOSTREAMS) && \ defined(CGAL_LINKED_WITH_BOOST_SERIALIZATION)) void save_configuration (std::ostream& output) const { - boost::iostreams::filtering_ostream outs; - outs.push(boost::iostreams::gzip_compressor()); - outs.push(output); - boost::archive::text_oarchive oas(outs); - oas << BOOST_SERIALIZATION_NVP(*m_rfc); + m_rfc->write(output); } #endif /*! - \brief Loads a configuration from the stream `input`. + \brief loads a configuration from the stream `input`. - The input file should be a GZIP container written by the + The input file should be a binary file written by the `save_configuration()` method. The feature set of the classifier should contain the exact same features in the exact same order as the ones present when the file was generated using `save_configuration()`. + + \warning If the file you are trying to load was saved using CGAL + 5.1 or earlier, you have to convert it first using + `convert_deprecated_configuration_to_new_format()` as the exchange + format for ETHZ Random Forest changed in CGAL 5.2. + */ #if defined(DOXYGEN_RUNNING) || \ (defined(CGAL_LINKED_WITH_BOOST_IOSTREAMS) && \ @@ -316,9 +320,51 @@ public: void load_configuration (std::istream& input) { CGAL::internal::liblearning::RandomForest::ForestParams params; - if (m_rfc != nullptr) - delete m_rfc; - m_rfc = new Forest (params); + m_rfc = std::make_shared (params); + + m_rfc->read(input); + } +#endif + + /// @} + + /// \name Deprecated Input/Output + /// @{ + + /*! + \brief converts a deprecated configuration (in compressed ASCII + format) to a new configuration (in binary format). + + The input file should be a GZIP container written by the + `save_configuration()` method from CGAL 5.1 and earlier. The + output is a valid configuration for CGAL 5.2 and later. + + \note This function depends on the Boost libraries + [Serialization](https://www.boost.org/libs/serialization) and + [IO Streams](https://www.boost.org/libs/iostreams) (compiled with the GZIP dependency). + */ +#if defined(DOXYGEN_RUNNING) || \ + (defined(CGAL_LINKED_WITH_BOOST_IOSTREAMS) && \ + defined(CGAL_LINKED_WITH_BOOST_SERIALIZATION)) + static void convert_deprecated_configuration_to_new_format (std::istream& input, std::ostream& output) + { + Label_set dummy_labels; + Feature_set dummy_features; + Random_forest_classifier classifier (dummy_labels, dummy_features); + classifier.load_deprecated_configuration(input); + classifier.save_configuration(output); + } +#endif + +/// @} + + /// \cond SKIP_IN_MANUAL +#if defined(CGAL_LINKED_WITH_BOOST_IOSTREAMS) && \ + defined(CGAL_LINKED_WITH_BOOST_SERIALIZATION) + void load_deprecated_configuration (std::istream& input) + { + CGAL::internal::liblearning::RandomForest::ForestParams params; + m_rfc = std::make_shared (params); boost::iostreams::filtering_istream ins; ins.push(boost::iostreams::gzip_decompressor()); @@ -327,8 +373,8 @@ public: ias >> BOOST_SERIALIZATION_NVP(*m_rfc); } #endif + /// \endcond -/// @} }; diff --git a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/common-libraries.hpp b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/common-libraries.hpp index 97e13f532ce..e2fdfd42c87 100644 --- a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/common-libraries.hpp +++ b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/common-libraries.hpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -109,6 +110,30 @@ struct ForestParams { ar & BOOST_SERIALIZATION_NVP(sample_reduction); } #endif + + void write (std::ostream& os) + { + I_Binary_write_size_t_into_uinteger32 (os, n_classes); + I_Binary_write_size_t_into_uinteger32 (os, n_features); + I_Binary_write_size_t_into_uinteger32 (os, n_samples); + I_Binary_write_size_t_into_uinteger32 (os, n_in_bag_samples); + I_Binary_write_size_t_into_uinteger32 (os, max_depth); + I_Binary_write_size_t_into_uinteger32 (os, n_trees); + I_Binary_write_size_t_into_uinteger32 (os, min_samples_per_node); + I_Binary_write_float32 (os, sample_reduction); + } + + void read (std::istream& is) + { + I_Binary_read_size_t_from_uinteger32 (is, n_classes); + I_Binary_read_size_t_from_uinteger32 (is, n_features); + I_Binary_read_size_t_from_uinteger32 (is, n_samples); + I_Binary_read_size_t_from_uinteger32 (is, n_in_bag_samples); + I_Binary_read_size_t_from_uinteger32 (is, max_depth); + I_Binary_read_size_t_from_uinteger32 (is, n_trees); + I_Binary_read_size_t_from_uinteger32 (is, min_samples_per_node); + I_Binary_read_float32 (is, sample_reduction); + } }; struct QuadraticSplitter { @@ -248,6 +273,18 @@ struct AxisAlignedSplitter { ar & BOOST_SERIALIZATION_NVP(threshold); } #endif + + void write (std::ostream& os) + { + os.write((char*)(&feature), sizeof(int)); + os.write((char*)(&threshold), sizeof(FeatureType)); + } + + void read (std::istream& is) + { + is.read((char*)(&feature), sizeof(int)); + is.read((char*)(&threshold), sizeof(FeatureType)); + } }; struct AxisAlignedRandomSplitGenerator { diff --git a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp index 6ffe0e0b719..4611becf711 100644 --- a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp +++ b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/forest.hpp @@ -31,7 +31,7 @@ #endif #include - +#include #include #ifdef CGAL_LINKED_WITH_TBB @@ -164,10 +164,10 @@ public: f (seed_start, sample_idxes, trees, samples, labels, params.n_in_bag_samples, split_generator); #ifndef CGAL_LINKED_WITH_TBB - CGAL_static_assertion_msg (!(boost::is_convertible::value), + CGAL_static_assertion_msg (!(std::is_convertible::value), "Parallel_tag is enabled but TBB is unavailable."); #else - if (boost::is_convertible::value) + if (std::is_convertible::value) { tbb::parallel_for(tbb::blocked_range(nb_trees, nb_trees + params.n_trees), f); } @@ -232,6 +232,28 @@ public: } #endif + void write (std::ostream& os) + { + params.write(os); + + I_Binary_write_size_t_into_uinteger32 (os, trees.size()); + for (std::size_t i_tree = 0; i_tree < trees.size(); ++i_tree) + trees[i_tree].write(os); + } + + void read (std::istream& is) + { + params.read(is); + + std::size_t nb_trees; + I_Binary_read_size_t_from_uinteger32 (is, nb_trees); + for (std::size_t i = 0; i < nb_trees; ++ i) + { + trees.push_back (new TreeType(¶ms)); + trees.back().read(is); + } + } + void get_feature_usage (std::vector& count) const { for (std::size_t i_tree = 0; i_tree < trees.size(); ++i_tree) diff --git a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/node.hpp b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/node.hpp index f510119a557..75ecc1037e6 100644 --- a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/node.hpp +++ b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/node.hpp @@ -22,6 +22,8 @@ #include "../dataview.h" #include "common-libraries.hpp" +#include + #if defined(CGAL_LINKED_WITH_BOOST_IOSTREAMS) && defined(CGAL_LINKED_WITH_BOOST_SERIALIZATION) #include #include @@ -253,9 +255,46 @@ public: } #endif + void write (std::ostream& os) + { + I_Binary_write_bool (os, is_leaf); + I_Binary_write_size_t_into_uinteger32 (os, n_samples); + I_Binary_write_size_t_into_uinteger32 (os, depth); + splitter.write(os); + + for (const float& f : node_dist) + I_Binary_write_float32 (os, f); + + if (!is_leaf) + { + left->write(os); + right->write(os); + } + } + + void read (std::istream& is) + { + I_Binary_read_bool (is, is_leaf); + I_Binary_read_size_t_from_uinteger32 (is, n_samples); + I_Binary_read_size_t_from_uinteger32 (is, depth); + splitter.read(is); + + node_dist.resize(params->n_classes, 0.0f); + for (std::size_t i = 0; i < node_dist.size(); ++ i) + I_Binary_read_float32 (is, node_dist[i]); + + if (!is_leaf) + { + left.reset(new Derived(depth + 1, params)); + right.reset(new Derived(depth + 1, params)); + left->read(is); + right->read(is); + } + } + void get_feature_usage (std::vector& count) const { - if (!is_leaf) + if (!is_leaf && splitter.feature != -1) { count[std::size_t(splitter.feature)] ++; left->get_feature_usage(count); diff --git a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/tree.hpp b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/tree.hpp index c8a07f020d7..ba75c6e2f98 100644 --- a/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/tree.hpp +++ b/Classification/include/CGAL/Classification/ETHZ/internal/random-forest/tree.hpp @@ -129,6 +129,17 @@ public: } #endif + void write (std::ostream& os) + { + root_node->write(os); + } + + void read (std::istream& is) + { + root_node.reset(new NodeT(0, params)); + root_node->read(is); + } + void get_feature_usage (std::vector& count) const { root_node->get_feature_usage(count); diff --git a/Classification/include/CGAL/Classification/Evaluation.h b/Classification/include/CGAL/Classification/Evaluation.h index 071f6ab8c9f..eeff26f73d6 100644 --- a/Classification/include/CGAL/Classification/Evaluation.h +++ b/Classification/include/CGAL/Classification/Evaluation.h @@ -17,9 +17,10 @@ #include #include -#include #include +#include + #include #include // for std::isnan @@ -27,6 +28,7 @@ namespace CGAL { namespace Classification { + /*! \ingroup PkgClassificationDataStructures @@ -35,98 +37,103 @@ namespace Classification { */ class Evaluation { - mutable std::map m_map_labels; - - std::vector m_precision; - std::vector m_recall; - std::vector m_iou; // intersection over union - float m_accuracy; - float m_mean_iou; - float m_mean_f1; + const Label_set& m_labels; + std::vector > m_confusion; // confusion matrix public: - /// \name Constructor + /// \name Constructors /// @{ + /*! + \brief instantiates an empty evaluation object. -/*! + \param labels labels used. + */ + Evaluation (const Label_set& labels) + : m_labels (labels) + { + init(); + } - \brief Instantiates an evaluation object and computes all - measurements. + /*! - \param labels labels used. + \brief instantiates an evaluation object and computes all + measurements. - \param ground_truth vector of label indices: it should contain the - index of the corresponding label in the `Label_set` provided in the - constructor. Input items that do not have a ground truth information - should be given the value `-1`. + \param labels labels used. - \param result similar to `ground_truth` but contained the result of - a classification. + \param ground_truth vector of label indices: it should contain the + index of the corresponding label in the `Label_set` provided in the + constructor. Input items that do not have a ground truth information + should be given the value `-1`. -*/ + \param result similar to `ground_truth` but contained the result of + a classification. + + */ template Evaluation (const Label_set& labels, const GroundTruthIndexRange& ground_truth, const ResultIndexRange& result) - : m_precision (labels.size()), - m_recall (labels.size()), - m_iou (labels.size()) + : m_labels (labels) { - for (std::size_t i = 0; i < labels.size(); ++ i) - m_map_labels[labels[i]] = i; + init(); + append(ground_truth, result); + } - std::vector true_positives (labels.size()); - std::vector false_positives (labels.size()); - std::vector false_negatives (labels.size()); + /// \cond SKIP_IN_MANUAL + void init() + { + m_confusion.resize (m_labels.size()); + for (std::size_t i = 0; i < m_confusion.size(); ++ i) + m_confusion[i].resize (m_labels.size(), 0); + } - std::size_t sum_true_positives = 0; - std::size_t total = 0; + bool label_has_ground_truth (std::size_t label_idx) const + { + for (std::size_t i = 0; i < m_labels.size(); ++ i) + if (m_confusion[i][label_idx] != 0) + return true; + return false; + } + /// \endcond - for (const auto& zip : CGAL::make_range (boost::make_zip_iterator - (boost::make_tuple(ground_truth.begin(), result.begin())), - boost::make_zip_iterator - (boost::make_tuple(ground_truth.end(), result.end())))) + /// @} + + /// \name Modification + /// @{ + + /*! + \brief appends more items to the evaluation object. + + \param ground_truth vector of label indices: it should contain the + index of the corresponding label in the `Label_set` provided in the + constructor. Input items that do not have a ground truth information + should be given the value `-1`. + + \param result similar to `ground_truth` but contained the result of + a classification. + + */ + template + void append (const GroundTruthIndexRange& ground_truth, + const ResultIndexRange& result) + { + CGAL_precondition (m_labels.is_valid_ground_truth (ground_truth)); + CGAL_precondition (m_labels.is_valid_ground_truth (result)); + + for (const auto& p : CGAL::make_range + (boost::make_zip_iterator(boost::make_tuple(ground_truth.begin(), result.begin())), + boost::make_zip_iterator(boost::make_tuple(ground_truth.end(), result.end())))) { - int gt = static_cast(boost::get<0>(zip)); - int res = static_cast(boost::get<1>(zip)); + int gt = static_cast(boost::get<0>(p)); + int res = static_cast(boost::get<1>(p)); if (gt == -1 || res == -1) continue; - ++ total; - if (gt == res) - { - ++ true_positives[gt]; - ++ sum_true_positives; - continue; - } - ++ false_positives[res]; - ++ false_negatives[gt]; + + ++ m_confusion[std::size_t(res)][std::size_t(gt)]; } - - m_mean_iou = 0.; - m_mean_f1 = 0.; - - std::size_t correct_labels = 0; - - for (std::size_t j = 0; j < labels.size(); ++ j) - { - m_precision[j] = true_positives[j] / float(true_positives[j] + false_positives[j]); - m_recall[j] = true_positives[j] / float(true_positives[j] + false_negatives[j]); - m_iou[j] = true_positives[j] / float(true_positives[j] + false_positives[j] + false_negatives[j]); - - if (std::isnan(m_iou[j])) - continue; - - ++ correct_labels; - m_mean_iou += m_iou[j]; - m_mean_f1 += 2.f * (m_precision[j] * m_recall[j]) - / (m_precision[j] + m_recall[j]); - } - - m_mean_iou /= correct_labels; - m_mean_f1 /= correct_labels; - m_accuracy = sum_true_positives / float(total); } /// @} @@ -134,10 +141,20 @@ public: /// \name Label Evaluation /// @{ + /*! + \brief returns the number of items whose ground truth is + `ground_truth` and which were classified as `result`. + */ + std::size_t confusion (Label_handle ground_truth, Label_handle result) + { + std::size_t idx_gt = ground_truth->index(); + std::size_t idx_r = result->index(); + return m_confusion[idx_gt][idx_r]; + } /*! - \brief Returns the precision of the training for the given label. + \brief returns the precision of the training for the given label. Precision is the number of true positives divided by the sum of the true positives and the false positives. @@ -145,12 +162,23 @@ public: */ float precision (Label_handle label) const { - return m_precision[m_map_labels[label]]; + std::size_t idx = label->index(); + if (!label_has_ground_truth(idx)) + return std::numeric_limits::quiet_NaN(); + + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + total += m_confusion[idx][i]; + + if (total == 0) + return 0.f; + + return m_confusion[idx][idx] / float(total); } /*! - \brief Returns the recall of the training for the given label. + \brief returns the recall of the training for the given label. Recall is the number of true positives divided by the sum of the true positives and the false negatives. @@ -158,12 +186,19 @@ public: */ float recall (Label_handle label) const { - return m_recall[m_map_labels[label]]; + std::size_t idx = label->index(); + if (!label_has_ground_truth(idx)) + return std::numeric_limits::quiet_NaN(); + + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + total += m_confusion[i][idx]; + return m_confusion[idx][idx] / float(total); } /*! - \brief Returns the \f$F_1\f$ score of the training for the given label. + \brief returns the \f$F_1\f$ score of the training for the given label. \f$F_1\f$ score is the harmonic mean of `precision()` and `recall()`: @@ -174,13 +209,17 @@ public: */ float f1_score (Label_handle label) const { - std::size_t label_idx = m_map_labels[label]; - return 2.f * (m_precision[label_idx] * m_recall[label_idx]) - / (m_precision[label_idx] + m_recall[label_idx]); + float p = precision(label); + float r = recall(label); + + if (p == 0.f && r == 0.f) + return 0.f; + + return 2.f * p * r / (p + r); } /*! - \brief Returns the intersection over union of the training for the + \brief returns the intersection over union of the training for the given label. Intersection over union is the number of true positives divided by @@ -189,7 +228,17 @@ public: */ float intersection_over_union (Label_handle label) const { - return m_iou[m_map_labels[label]]; + std::size_t idx = label->index(); + + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + { + total += m_confusion[i][idx]; + if (i != idx) + total += m_confusion[idx][i]; + } + + return m_confusion[idx][idx] / float(total); } /// @} @@ -197,26 +246,226 @@ public: /// \name Global Evaluation /// @{ + /*! + \brief returns the number of misclassified items. + */ + std::size_t number_of_misclassified_items() const + { + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + for (std::size_t j = 0; j < m_labels.size(); ++ j) + if (i != j) + total += m_confusion[i][j]; + return total; + } /*! - \brief Returns the accuracy of the training. + \brief returns the total number of items used for evaluation. + */ + std::size_t number_of_items() const + { + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + for (std::size_t j = 0; j < m_labels.size(); ++ j) + total += m_confusion[i][j]; + return total; + } + + /*! + \brief returns the accuracy of the training. Accuracy is the total number of true positives divided by the total number of provided inliers. */ - float accuracy() const { return m_accuracy; } + float accuracy() const + { + std::size_t true_positives = 0; + std::size_t total = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + { + true_positives += m_confusion[i][i]; + for (std::size_t j = 0; j < m_labels.size(); ++ j) + total += m_confusion[i][j]; + } + return true_positives / float(total); + } /*! - \brief Returns the mean \f$F_1\f$ score of the training over all + \brief returns the mean \f$F_1\f$ score of the training over all labels (see `f1_score()`). */ - float mean_f1_score() const { return m_mean_f1; } + float mean_f1_score() const + { + float mean = 0; + std::size_t nb = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + if (label_has_ground_truth(i)) + { + mean += f1_score(m_labels[i]); + ++ nb; + } + return mean / nb; + } /*! - \brief Returns the mean intersection over union of the training + \brief returns the mean intersection over union of the training over all labels (see `intersection_over_union()`). */ - float mean_intersection_over_union() const { return m_mean_iou; } + float mean_intersection_over_union() const + { + float mean = 0; + std::size_t nb = 0; + for (std::size_t i = 0; i < m_labels.size(); ++ i) + { + float iou = intersection_over_union(m_labels[i]); + if (!std::isnan(iou)) + { + mean += iou; + ++ nb; + } + } + return mean / nb; + } + + /// @} + + /// \name Output Formatting Functions + /// @{ + + /*! + \brief outputs the evaluation in a simple ASCII format to the stream `os`. + */ + friend std::ostream& operator<< (std::ostream& os, const Evaluation& evaluation) + { + os << "Evaluation of classification:" << std::endl; + os << " * Global results:" << std::endl; + os << " - " << evaluation.number_of_misclassified_items() + << " misclassified item(s) out of " << evaluation.number_of_items() << std::endl + << " - Accuracy = " << evaluation.accuracy() << std::endl + << " - Mean F1 score = " << evaluation.mean_f1_score() << std::endl + << " - Mean IoU = " << evaluation.mean_intersection_over_union() << std::endl; + os << " * Detailed results:" << std::endl; + for (std::size_t i = 0; i < evaluation.m_labels.size(); ++ i) + { + os << " - \"" << evaluation.m_labels[i]->name() << "\": "; + if (evaluation.label_has_ground_truth(i)) + os << "Precision = " << evaluation.precision(evaluation.m_labels[i]) << " ; " + << "Recall = " << evaluation.recall(evaluation.m_labels[i]) << " ; " + << "F1 score = " << evaluation.f1_score(evaluation.m_labels[i]) << " ; " + << "IoU = " << evaluation.intersection_over_union(evaluation.m_labels[i]) << std::endl; + else + os << "(no ground truth)" << std::endl; + } + return os; + } + + /*! + \brief outputs the evaluation as an HTML page to the stream `os`. + */ + static std::ostream& output_to_html (std::ostream& os, const Evaluation& evaluation) + { + os << "" << std::endl + << "" << std::endl + << "" << std::endl + << "" << std::endl + << "Evaluation of CGAL Classification results" << std::endl + << "" << std::endl + << "" << std::endl + << "

    Evaluation of CGAL Classification results

    " << std::endl; + + os << "

    Global Results

    " << std::endl + << "
      " << std::endl + << "
    • " << evaluation.number_of_misclassified_items() + << " misclassified item(s) out of " << evaluation.number_of_items() << "
    • " << std::endl + << "
    • Accuracy = " << evaluation.accuracy() << "
    • " << std::endl + << "
    • Mean F1 score = " << evaluation.mean_f1_score() << "
    • " << std::endl + << "
    • Mean IoU = " << evaluation.mean_intersection_over_union() << "
    • " << std::endl + << "
    " << std::endl; + + const Label_set& labels = evaluation.m_labels; + + os << "

    Detailed Results

    " << std::endl + << "" << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl; + for (std::size_t i = 0; i < labels.size(); ++ i) + if (evaluation.label_has_ground_truth(i)) + os << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl; + else + os << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl + << " " << std::endl; + + os << "
    LabelPrecisionRecallF1 scoreIoU
    " << labels[i]->name() << "" << evaluation.precision(labels[i]) << "" << evaluation.recall(labels[i]) << "" << evaluation.f1_score(labels[i]) << "" << evaluation.intersection_over_union(labels[i]) << "
    " << labels[i]->name() << "(no ground truth)
    " << std::endl; + + os << "

    Confusion Matrix

    " << std::endl + << "" << std::endl + << " " << std::endl + << " " << std::endl; + for (std::size_t i = 0; i < labels.size(); ++ i) + os << " " << std::endl; + os << " " << std::endl; + os << " " << std::endl; + + std::vector sums (labels.size(), 0); + for (std::size_t i = 0; i < labels.size(); ++ i) + { + os << " " << std::endl + << " " << std::endl; + std::size_t sum = 0; + for (std::size_t j = 0; j < labels.size(); ++ j) + { + if (i == j) + os << " " << std::endl; + else + os << " " << std::endl; + sum += evaluation.m_confusion[i][j]; + sums[j] += evaluation.m_confusion[i][j]; + } + os << " " << std::endl; + os << " " << std::endl; + } + + os << " " << std::endl + << " " << std::endl; + std::size_t total = 0; + for (std::size_t j = 0; j < labels.size(); ++ j) + { + os << " " << std::endl; + total += sums[j]; + } + os << " " << std::endl + << " " << std::endl + << "
    " << labels[i]->name() << "PREDICTIONS
    " << labels[i]->name() << "" << evaluation.m_confusion[i][j] << "" << evaluation.m_confusion[i][j] << "" << sum << "
    GROUND TRUTH" << sums[j] << "" << total << "
    " << std::endl + << "

    This page was generated by the CGAL \ +Classification package.

    " << std::endl + << "" << std::endl + << "" << std::endl; + + return os; + } /// @} diff --git a/Classification/include/CGAL/Classification/Feature/Cluster_mean_of_feature.h b/Classification/include/CGAL/Classification/Feature/Cluster_mean_of_feature.h index 0a3846fe2aa..4f39bcfaf62 100644 --- a/Classification/include/CGAL/Classification/Feature/Cluster_mean_of_feature.h +++ b/Classification/include/CGAL/Classification/Feature/Cluster_mean_of_feature.h @@ -40,7 +40,7 @@ class Cluster_mean_of_feature : public CGAL::Classification::Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \tparam ClusterRange model of `ConstRange`. Its iterator type is `RandomAccessIterator` and its value type is the key type of diff --git a/Classification/include/CGAL/Classification/Feature/Cluster_size.h b/Classification/include/CGAL/Classification/Feature/Cluster_size.h index 52f8fac9d3d..772c87b8fa9 100644 --- a/Classification/include/CGAL/Classification/Feature/Cluster_size.h +++ b/Classification/include/CGAL/Classification/Feature/Cluster_size.h @@ -37,7 +37,7 @@ class Cluster_size : public CGAL::Classification::Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \tparam ClusterRange model of `ConstRange`. Its iterator type is `RandomAccessIterator` and its value type is the key type of diff --git a/Classification/include/CGAL/Classification/Feature/Cluster_variance_of_feature.h b/Classification/include/CGAL/Classification/Feature/Cluster_variance_of_feature.h index dfa4bfe5891..30817fef411 100644 --- a/Classification/include/CGAL/Classification/Feature/Cluster_variance_of_feature.h +++ b/Classification/include/CGAL/Classification/Feature/Cluster_variance_of_feature.h @@ -40,7 +40,7 @@ class Cluster_variance_of_feature : public CGAL::Classification::Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \tparam ClusterRange model of `ConstRange`. Its iterator type is `RandomAccessIterator` and its value type is the key type of diff --git a/Classification/include/CGAL/Classification/Feature/Cluster_vertical_extent.h b/Classification/include/CGAL/Classification/Feature/Cluster_vertical_extent.h index ed977c52da6..07d3a2214a5 100644 --- a/Classification/include/CGAL/Classification/Feature/Cluster_vertical_extent.h +++ b/Classification/include/CGAL/Classification/Feature/Cluster_vertical_extent.h @@ -40,7 +40,7 @@ class Cluster_vertical_extent : public CGAL::Classification::Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \tparam ClusterRange model of `ConstRange`. Its iterator type is `RandomAccessIterator` and its value type is the key type of diff --git a/Classification/include/CGAL/Classification/Feature/Color_channel.h b/Classification/include/CGAL/Classification/Feature/Color_channel.h index 8dfaa93c97c..b0296d191bb 100644 --- a/Classification/include/CGAL/Classification/Feature/Color_channel.h +++ b/Classification/include/CGAL/Classification/Feature/Color_channel.h @@ -80,7 +80,7 @@ private: public: /*! - \brief Constructs a feature based on the given color channel. + \brief constructs a feature based on the given color channel. \param input point range. \param color_map property map to access the colors of the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Distance_to_plane.h b/Classification/include/CGAL/Classification/Feature/Distance_to_plane.h index 19b6b83a959..46adeec1b41 100644 --- a/Classification/include/CGAL/Classification/Feature/Distance_to_plane.h +++ b/Classification/include/CGAL/Classification/Feature/Distance_to_plane.h @@ -46,8 +46,7 @@ namespace Feature { template class Distance_to_plane : public Feature_base { - - typedef typename CGAL::Kernel_traits::Kernel Kernel; + using Kernel = typename CGAL::Kernel_traits::Kernel; #ifdef CGAL_CLASSIFICATION_PRECOMPUTE_FEATURES std::vector distance_to_plane_feature; @@ -59,7 +58,7 @@ class Distance_to_plane : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Echo_scatter.h b/Classification/include/CGAL/Classification/Feature/Echo_scatter.h index b2206910102..9fb63252d6e 100644 --- a/Classification/include/CGAL/Classification/Feature/Echo_scatter.h +++ b/Classification/include/CGAL/Classification/Feature/Echo_scatter.h @@ -52,9 +52,9 @@ template Grid; + using Grid = Classification::Planimetric_grid; private: - typedef Classification::Image Image_cfloat; + using Image_cfloat = Classification::Image; const Grid& grid; Image_cfloat Scatter; @@ -62,7 +62,7 @@ private: public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param echo_map property map to access the echo values of the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Elevation.h b/Classification/include/CGAL/Classification/Feature/Elevation.h index 1205c757403..175b20b6a44 100644 --- a/Classification/include/CGAL/Classification/Feature/Elevation.h +++ b/Classification/include/CGAL/Classification/Feature/Elevation.h @@ -50,11 +50,9 @@ namespace Feature { template class Elevation : public Feature_base { - typedef typename GeomTraits::Iso_cuboid_3 Iso_cuboid_3; - - typedef Image Image_float; - typedef Image Image_cfloat; - typedef Planimetric_grid Grid; + using Image_float = Image; + using Image_cfloat = Image; + using Grid = Planimetric_grid; const PointRange& input; PointMap point_map; @@ -66,7 +64,7 @@ class Elevation : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Height_above.h b/Classification/include/CGAL/Classification/Feature/Height_above.h index 62eac6f20e2..b59b108c1ac 100644 --- a/Classification/include/CGAL/Classification/Feature/Height_above.h +++ b/Classification/include/CGAL/Classification/Feature/Height_above.h @@ -49,10 +49,8 @@ namespace Feature { template class Height_above : public Feature_base { - typedef typename GeomTraits::Iso_cuboid_3 Iso_cuboid_3; - - typedef Image Image_float; - typedef Planimetric_grid Grid; + using Image_float = Image; + using Grid = Planimetric_grid; const PointRange& input; PointMap point_map; @@ -62,7 +60,7 @@ class Height_above : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Height_below.h b/Classification/include/CGAL/Classification/Feature/Height_below.h index 0eae37370f6..22371934155 100644 --- a/Classification/include/CGAL/Classification/Feature/Height_below.h +++ b/Classification/include/CGAL/Classification/Feature/Height_below.h @@ -49,8 +49,6 @@ namespace Feature { template class Height_below : public Feature_base { - typedef typename GeomTraits::Iso_cuboid_3 Iso_cuboid_3; - typedef Image Image_float; typedef Planimetric_grid Grid; @@ -62,7 +60,7 @@ class Height_below : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Simple_feature.h b/Classification/include/CGAL/Classification/Feature/Simple_feature.h index 12efb1563be..8dd5f59168c 100644 --- a/Classification/include/CGAL/Classification/Feature/Simple_feature.h +++ b/Classification/include/CGAL/Classification/Feature/Simple_feature.h @@ -42,7 +42,7 @@ class Simple_feature : public Feature_base public: /*! - \brief Constructs the feature using an input range and a property map. + \brief constructs the feature using an input range and a property map. \param input point range. \param property_map property map to access scalar field. diff --git a/Classification/include/CGAL/Classification/Feature/Vertical_dispersion.h b/Classification/include/CGAL/Classification/Feature/Vertical_dispersion.h index c173f70acca..2a5c8e6e9c7 100644 --- a/Classification/include/CGAL/Classification/Feature/Vertical_dispersion.h +++ b/Classification/include/CGAL/Classification/Feature/Vertical_dispersion.h @@ -56,8 +56,8 @@ namespace Feature { template class Vertical_dispersion : public Feature_base { - typedef Classification::Image Image_cfloat; - typedef Classification::Planimetric_grid Grid; + using Image_cfloat = Classification::Image; + using Grid = Classification::Planimetric_grid; const Grid& grid; Image_cfloat Dispersion; @@ -65,7 +65,7 @@ class Vertical_dispersion : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Vertical_range.h b/Classification/include/CGAL/Classification/Feature/Vertical_range.h index 95fc5042e18..45b9c98d3ee 100644 --- a/Classification/include/CGAL/Classification/Feature/Vertical_range.h +++ b/Classification/include/CGAL/Classification/Feature/Vertical_range.h @@ -49,10 +49,8 @@ namespace Feature { template class Vertical_range : public Feature_base { - typedef typename GeomTraits::Iso_cuboid_3 Iso_cuboid_3; - - typedef Image Image_float; - typedef Planimetric_grid Grid; + using Image_float = Image; + using Grid = Planimetric_grid; const PointRange& input; PointMap point_map; @@ -62,7 +60,7 @@ class Vertical_range : public Feature_base public: /*! - \brief Constructs the feature. + \brief constructs the feature. \param input point range. \param point_map property map to access the input points. diff --git a/Classification/include/CGAL/Classification/Feature/Verticality.h b/Classification/include/CGAL/Classification/Feature/Verticality.h index 8bfe7537bc1..2ef8cac6376 100644 --- a/Classification/include/CGAL/Classification/Feature/Verticality.h +++ b/Classification/include/CGAL/Classification/Feature/Verticality.h @@ -46,7 +46,7 @@ class Verticality : public Feature_base public: /*! - \brief Constructs the feature using local eigen analysis. + \brief constructs the feature using local eigen analysis. \tparam InputRange model of `ConstRange`. Its iterator type is `RandomAccessIterator`. @@ -64,7 +64,7 @@ public: /*! - \brief Constructs the feature using provided normals of points. + \brief constructs the feature using provided normals of points. \tparam PointRange model of `ConstRange`. Its iterator type is `RandomAccessIterator` and its value type is the key type of diff --git a/Classification/include/CGAL/Classification/Feature_base.h b/Classification/include/CGAL/Classification/Feature_base.h index 469bf079bc9..89ba6e60384 100644 --- a/Classification/include/CGAL/Classification/Feature_base.h +++ b/Classification/include/CGAL/Classification/Feature_base.h @@ -14,8 +14,8 @@ #include -#include - +#include +#include #include namespace CGAL { @@ -42,18 +42,18 @@ public: /// \endcond /*! - \brief Returns the name of the feature (initialized to + \brief returns the name of the feature (initialized to `abstract_feature` for `Feature_base`). */ const std::string& name() const { return m_name; } /*! - \brief Changes the name of the feature. + \brief changes the name of the feature. */ void set_name (const std::string& name) { m_name = name; } /*! - \brief Returns the value taken by the feature for at the item for + \brief returns the value taken by the feature for at the item for the item at position `index`. This method must be implemented by inherited classes. */ @@ -72,7 +72,6 @@ public: */ class Feature_handle { }; #else -//typedef boost::shared_ptr Feature_handle; class Feature_set; @@ -80,19 +79,23 @@ class Feature_handle { friend Feature_set; - boost::shared_ptr > m_base; + using Feature_base_ptr = std::unique_ptr; + std::shared_ptr m_base; - template - Feature_handle (Feature* f) : m_base (new boost::shared_ptr(f)) { } - - template - void attach (Feature* f) const + template + Feature_handle (Feature_ptr f) + : m_base (std::make_shared(std::move(f))) { - *m_base = boost::shared_ptr(f); + } + + template + void attach (Feature_ptr f) + { + *m_base = std::move(f); } public: - Feature_handle() : m_base (new boost::shared_ptr()) { } + Feature_handle() : m_base (std::make_shared()) { } Feature_base& operator*() { return **m_base; } @@ -107,6 +110,17 @@ public: #endif +/*! + \ingroup PkgClassificationFeature + + \brief casts a feature handle to a specialized feature pointer. +*/ +template +FeatureType* feature_cast (Feature_handle fh) +{ + return dynamic_cast(&*(fh)); +} + } // namespace Classification diff --git a/Classification/include/CGAL/Classification/Feature_set.h b/Classification/include/CGAL/Classification/Feature_set.h index 13fb59840e5..2573c3abde6 100644 --- a/Classification/include/CGAL/Classification/Feature_set.h +++ b/Classification/include/CGAL/Classification/Feature_set.h @@ -16,15 +16,14 @@ #include -#include - #ifdef CGAL_LINKED_WITH_TBB -#include #include #endif // CGAL_LINKED_WITH_TBB #include +#include #include +#include namespace CGAL { @@ -40,7 +39,7 @@ the addition and the deletion of features. */ class Feature_set { - typedef std::vector Base; + using Base = std::vector; Base m_features; struct Compare_name @@ -54,42 +53,35 @@ class Feature_set }; #ifdef CGAL_LINKED_WITH_TBB - tbb::task_group* m_tasks; + std::unique_ptr m_tasks; #endif // CGAL_LINKED_WITH_TBB public: +#ifdef DOXYGEN_RUNNING + using const_iterator = unspecified_type; ///< A random access constant iterator with value type `Feature_handle`. + using iterator = unspecified_type; ///< A random access iterator with value type `Feature_handle`. +#else + using const_iterator = std::vector::const_iterator; + using iterator = std::vector::iterator; +#endif + /// \name Constructor /// @{ /*! - \brief Creates an empty feature set. + \brief creates an empty feature set. */ Feature_set() -#ifdef CGAL_LINKED_WITH_TBB - : m_tasks(nullptr) -#endif { } /// @} - /// \cond SKIP_IN_MANUAL - virtual ~Feature_set() - { -#ifdef CGAL_LINKED_WITH_TBB - if (m_tasks != nullptr) - delete m_tasks; - for (std::size_t i = 0; i < m_adders.size(); ++ i) - delete m_adders[i]; -#endif - } - /// \endcond - /// \name Modifications /// @{ /*! - \brief Instantiates a new feature and adds it to the set. + \brief instantiates a new feature and adds it to the set. If several calls of `add()` are surrounded by `begin_parallel_additions()` and `end_parallel_additions()`, they @@ -113,20 +105,21 @@ public: Feature_handle add (T&& ... t) { #ifdef CGAL_LINKED_WITH_TBB - if (m_tasks != nullptr) + if (m_tasks) { m_features.push_back (Feature_handle()); - Parallel_feature_adder* adder - = new Parallel_feature_adder(m_features.back(), std::forward(t)...); - - m_adders.push_back (adder); + Parallel_feature_adder_ptr adder + = std::make_unique > + (m_features.back(), std::forward(t)...); m_tasks->run (*adder); + + m_adders.emplace_back (std::move (adder)); } else #endif { - m_features.push_back (Feature_handle (new Feature(std::forward(t)...))); + m_features.push_back (Feature_handle (std::make_unique(std::forward(t)...))); } return m_features.back(); } @@ -136,20 +129,21 @@ public: Feature_handle add_with_scale_id (std::size_t i, T&& ... t) { #ifdef CGAL_LINKED_WITH_TBB - if (m_tasks != nullptr) + if (m_tasks) { m_features.push_back (Feature_handle()); - Parallel_feature_adder* adder - = new Parallel_feature_adder(i, m_features.back(), std::forward(t)...); - - m_adders.push_back (adder); + Parallel_feature_adder_ptr adder + = std::make_unique > + (i, m_features.back(), std::forward(t)...); m_tasks->run (*adder); + + m_adders.emplace_back (std::move (adder)); } else #endif { - m_features.push_back (Feature_handle (new Feature(std::forward(t)...))); + m_features.push_back (Feature_handle (std::make_unique(std::forward(t)...))); m_features.back()->set_name (m_features.back()->name() + "_" + std::to_string(i)); } return m_features.back(); @@ -158,7 +152,7 @@ public: /*! - \brief Removes a feature. + \brief removes a feature. \param feature the handle to feature type that must be removed. @@ -177,7 +171,7 @@ public: } /*! - \brief Removes all features. + \brief removes all features. */ void clear () { @@ -190,16 +184,15 @@ public: /// @{ -#if defined(CGAL_LINKED_WITH_TBB) || defined(DOXYGEN_RUNNING) - /*! - \brief Initializes structures to compute features in parallel. + \brief initializes structures to compute features in parallel. If the user wants to add features in parallel, this function should be called before making several calls of `add()`. After the calls of `add()`, `end_parallel_additions()` should be called. - \note This function requires \ref thirdpartyTBB. + \note If \ref thirdpartyTBB is not available, this function does + nothing. \warning As arguments of `add()` are passed by reference and that new threads are started if `begin_parallel_additions()` is used, it is @@ -212,33 +205,33 @@ public: */ void begin_parallel_additions() { - m_tasks = new tbb::task_group; +#ifdef CGAL_LINKED_WITH_TBB + m_tasks = std::make_unique(); +#endif } /*! - \brief Waits for the end of parallel feature computation and + \brief waits for the end of parallel feature computation and clears dedicated data structures afterwards. If the user wants to add features in parallel, this function should be called after `begin_parallel_additions()` and several calls of `add()`. - \note This function requires \ref thirdpartyTBB. + \note If \ref thirdpartyTBB is not available, this function does + nothing. \sa `begin_parallel_additions()` */ void end_parallel_additions() { +#ifdef CGAL_LINKED_WITH_TBB m_tasks->wait(); - delete m_tasks; - m_tasks = nullptr; - - for (std::size_t i = 0; i < m_adders.size(); ++ i) - delete m_adders[i]; + m_tasks.release(); m_adders.clear(); - } #endif + } /// @} @@ -246,8 +239,13 @@ public: /// \name Access /// @{ + const_iterator begin() const { return m_features.begin(); } + iterator begin() { return m_features.begin(); } + const_iterator end() const { return m_features.end(); } + iterator end() { return m_features.end(); } + /*! - \brief Returns how many features are defined. + \brief returns how many features are defined. */ std::size_t size() const { @@ -256,7 +254,7 @@ public: /*! - \brief Returns the \f$i^{th}\f$ feature. + \brief returns the \f$i^{th}\f$ feature. */ Feature_handle operator[](std::size_t i) const { @@ -293,18 +291,18 @@ private: { std::size_t scale; mutable Feature_handle fh; - boost::shared_ptr > args; + std::shared_ptr > args; Parallel_feature_adder (Feature_handle fh, T&& ... t) : scale (std::size_t(-1)), fh (fh) { - args = boost::make_shared >(std::forward(t)...); + args = std::make_shared >(std::forward(t)...); } Parallel_feature_adder (std::size_t scale, Feature_handle fh, T&& ... t) : scale(scale), fh (fh) { - args = boost::make_shared >(std::forward(t)...); + args = std::make_shared >(std::forward(t)...); } template @@ -325,7 +323,7 @@ private: template void add_feature (Tuple& t, seq) const { - fh.attach (new Feature (std::forward(std::get(t))...)); + fh.attach (std::make_unique (std::forward(std::get(t))...)); if (scale != std::size_t(-1)) fh->set_name (fh->name() + "_" + std::to_string(scale)); } @@ -337,7 +335,11 @@ private: }; - std::vector m_adders; + using Abstract_parallel_feature_adder_ptr = std::unique_ptr; + template + using Parallel_feature_adder_ptr = std::unique_ptr >; + + std::vector m_adders; /// \endcond }; diff --git a/Classification/include/CGAL/Classification/Image.h b/Classification/include/CGAL/Classification/Image.h index 45759ed219d..924e39bde24 100644 --- a/Classification/include/CGAL/Classification/Image.h +++ b/Classification/include/CGAL/Classification/Image.h @@ -14,8 +14,8 @@ #include -#include #include +#include #define CGAL_CLASSIFICATION_IMAGE_SIZE_LIMIT 100000000 @@ -27,15 +27,15 @@ namespace Classification { template class Image { - typedef std::vector Vector; - typedef std::map Map; + using Vector = std::vector; + using Map = std::map; std::size_t m_width; std::size_t m_height; std::size_t m_depth; - boost::shared_ptr m_raw; - boost::shared_ptr m_sparse; + std::shared_ptr m_raw; + std::shared_ptr m_sparse; Type m_default; // Forbid using copy constructor @@ -45,7 +45,7 @@ class Image public: - Image () : m_width(0), m_height(0), m_depth(0), m_raw (nullptr) + Image () : m_width(0), m_height(0), m_depth(0) { } @@ -57,9 +57,9 @@ public: if (m_width * m_height * m_depth > 0) { if (m_width * m_height * m_depth < CGAL_CLASSIFICATION_IMAGE_SIZE_LIMIT) - m_raw = boost::shared_ptr (new Vector(m_width * m_height * m_depth)); + m_raw = std::make_shared (m_width * m_height * m_depth); else - m_sparse = boost::shared_ptr (new Map()); + m_sparse = std::make_shared (); } } @@ -69,8 +69,8 @@ public: void free() { - m_raw = boost::shared_ptr(); - m_sparse = boost::shared_ptr(); + m_raw.reset(); + m_sparse.reset(); } Image& operator= (const Image& other) @@ -94,7 +94,7 @@ public: Type& operator() (const std::size_t& x, const std::size_t& y, const std::size_t& z = 0) { - if (m_raw == boost::shared_ptr()) // sparse case + if (!m_raw) // sparse case { typename Map::iterator inserted = m_sparse->insert (std::make_pair (coord(x,y,z), Type())).first; @@ -105,7 +105,7 @@ public: } const Type& operator() (const std::size_t& x, const std::size_t& y, const std::size_t& z = 0) const { - if (m_raw == boost::shared_ptr()) // sparse case + if (!m_raw) // sparse case { typename Map::iterator found = m_sparse->find (coord(x,y,z)); if (found != m_sparse->end()) diff --git a/Classification/include/CGAL/Classification/Label.h b/Classification/include/CGAL/Classification/Label.h index 45b2545803c..6a21b630768 100644 --- a/Classification/include/CGAL/Classification/Label.h +++ b/Classification/include/CGAL/Classification/Label.h @@ -13,38 +13,89 @@ #define CGAL_CLASSIFICATION_LABEL_H #include +#include -#include +#include namespace CGAL { namespace Classification { +/// \cond SKIP_IN_MANUAL +class Label_set; +/// \endcond + /*! \ingroup PkgClassificationLabel -\brief %Classification label (for example: vegetation, ground, etc.) -defined as a set of relationships with classification features. +\brief %Classification label (for example: vegetation, ground, etc.). +\note Labels should always be constructed from a `CGAL::Classification::Label_set` object. */ class Label { private: std::string m_name; + std::size_t m_index; + std::size_t m_standard_index; + CGAL::Color m_color; + + friend Label_set; public: - /*! - \param name name of the classification label (e.g. vegetation). - */ - Label (std::string name) : m_name (name) { } + /// \cond SKIP_IN_MANUAL + // Undocumented: Labels should be created by the set + Label (std::string name, std::size_t index, std::size_t standard_index, + const CGAL::Color& color) + : m_name (name), m_index (index), m_standard_index (standard_index) + , m_color (color) + { } + /// \endcond + /// \name Access + /// @{ + + /*! + returns the name of the classification label (\a e.g. vegetation). + */ const std::string& name() const { return m_name; } - /// \cond SKIP_IN_MANUAL + /*! + returns the index of the classification label in the label set. + + \note This index cannot be changed by the user and is handled directly by the label set. + */ + std::size_t index() const { return m_index; } + + /*! + returns the standard index of the classification label (\a e.g. index in the ASPRS standard). + + \note This index is purely user-oriented and is not used by the classification algorithms. + */ + std::size_t standard_index() const { return m_standard_index; } + + /*! + returns the color used to represent the label. + + \note The color is purely user-oriented and is not used by the + classification algorithms. It is not to be confused with a color + attribute embedded in a data set which _can_ be used (see + `Color_channel`). + */ + const CGAL::Color& color() const { return m_color; } + + /// @} + + /// \name Modification + /// @{ + void set_name (const std::string& name) { m_name = name; } - /// \endcond + void set_standard_index(std::size_t idx) { m_standard_index = idx; } + void set_color (const Color& color) { m_color = color; } + + /// @} }; #ifdef DOXYGEN_RUNNING @@ -57,7 +108,7 @@ public: */ class Label_handle { }; #else -typedef boost::shared_ptr