From 2601b4824f281bf14b1f3b7f0934819f96486feb Mon Sep 17 00:00:00 2001 From: Valentin Platzgummer Date: Fri, 26 Jun 2020 11:19:36 +0200 Subject: [PATCH] SnakeWorker added --- QGCExternalLibs.pri | 15 +- libs/clipper/CMakeLists.txt | 8 - libs/clipper/Makefile | 296 - libs/clipper/clipper/.gitignore | 73 + libs/clipper/{ => clipper}/clipper.cpp | 9258 ++++---- libs/clipper/{include => clipper}/clipper.hpp | 812 +- libs/clipper/clipper/clipper.pro | 30 + libs/clipper/clipper/clipper_global.h | 18 + libs/clipper/cmake_install.cmake | 44 - libs/qwt/qwt_autogen/mocs_compilation.cpp | 26 + libs/shapelib/dbfadd | Bin 0 -> 105536 bytes .../dbfadd_autogen/mocs_compilation.cpp | 3 + libs/shapelib/dbfcreate | Bin 0 -> 106184 bytes .../dbfcreate_autogen/mocs_compilation.cpp | 3 + libs/shapelib/dbfdump | Bin 0 -> 111752 bytes .../dbfdump_autogen/mocs_compilation.cpp | 3 + .../shapelib/shp_autogen/mocs_compilation.cpp | 3 + libs/shapelib/shpadd | Bin 0 -> 151208 bytes .../shpadd_autogen/mocs_compilation.cpp | 3 + libs/shapelib/shpcreate | Bin 0 -> 147832 bytes .../shpcreate_autogen/mocs_compilation.cpp | 3 + libs/shapelib/shpdump | Bin 0 -> 151120 bytes .../shpdump_autogen/mocs_compilation.cpp | 3 + libs/shapelib/shprewind | Bin 0 -> 147184 bytes .../shprewind_autogen/mocs_compilation.cpp | 3 + libs/shapelib/shptreedump | Bin 0 -> 195808 bytes .../shptreedump_autogen/mocs_compilation.cpp | 3 + libs/snake/.gitignore | 73 + libs/snake/CMakeLists.txt | 18 - libs/snake/Makefile | 326 - libs/snake/cmake_install.cmake | 50 - libs/snake/{polylabel => }/mapbox/feature.hpp | 0 .../snake/{polylabel => }/mapbox/geometry.hpp | 0 .../{polylabel => }/mapbox/geometry/box.hpp | 0 .../{polylabel => }/mapbox/geometry/empty.hpp | 0 .../mapbox/geometry/envelope.hpp | 0 .../mapbox/geometry/for_each_point.hpp | 0 .../mapbox/geometry/geometry.hpp | 0 .../mapbox/geometry/line_string.hpp | 0 .../mapbox/geometry/multi_line_string.hpp | 0 .../mapbox/geometry/multi_point.hpp | 0 .../mapbox/geometry/multi_polygon.hpp | 0 .../{polylabel => }/mapbox/geometry/point.hpp | 0 .../mapbox/geometry/point_arithmetic.hpp | 0 .../mapbox/geometry/polygon.hpp | 0 .../{polylabel => }/mapbox/geometry_io.hpp | 0 .../snake/{polylabel => }/mapbox/optional.hpp | 0 .../mapbox/polylabel => mapbox}/polylabel.hpp | 0 .../mapbox/recursive_wrapper.hpp | 0 libs/snake/{polylabel => }/mapbox/variant.hpp | 0 .../{polylabel => }/mapbox/variant_io.hpp | 0 libs/snake/snake.cpp | 2 +- libs/snake/{include => }/snake.h | 0 libs/snake/snake.pro | 62 + libs/snake/snake_geometry.cpp | 5 +- libs/snake/{include => }/snake_geometry.h | 0 libs/snake/snake_geometry.h.orig | 36 - libs/snake/snake_global.h | 18 + libs/snake_old/catch.hpp | 17707 ++++++++++++++++ libs/snake_old/polylabel/mapbox/feature.hpp | 113 + libs/snake_old/polylabel/mapbox/geometry.hpp | 12 + .../polylabel/mapbox/geometry/box.hpp | 36 + .../polylabel/mapbox/geometry/empty.hpp | 18 + .../polylabel/mapbox/geometry/envelope.hpp | 33 + .../mapbox/geometry/for_each_point.hpp | 51 + .../polylabel/mapbox/geometry/geometry.hpp | 56 + .../polylabel/mapbox/geometry/line_string.hpp | 28 + .../mapbox/geometry/multi_line_string.hpp | 28 + .../polylabel/mapbox/geometry/multi_point.hpp | 28 + .../mapbox/geometry/multi_polygon.hpp | 28 + .../polylabel/mapbox/geometry/point.hpp | 42 + .../mapbox/geometry/point_arithmetic.hpp | 119 + .../polylabel/mapbox/geometry/polygon.hpp | 45 + .../polylabel/mapbox/geometry_io.hpp | 98 + libs/snake_old/polylabel/mapbox/optional.hpp | 74 + .../polylabel/mapbox/polylabel/polylabel.hpp | 178 + .../polylabel/mapbox/recursive_wrapper.hpp | 122 + libs/snake_old/polylabel/mapbox/variant.hpp | 901 + .../snake_old/polylabel/mapbox/variant_io.hpp | 45 + libs/snake_old/snake.cpp | 584 + libs/snake_old/snake.h | 143 + libs/snake_old/snake_geometry.cpp | 454 + libs/snake_old/snake_geometry.h | 136 + libs/{snake => snake_old}/test/CMakeLists.txt | 0 libs/{snake => snake_old}/test/Makefile | 0 .../test/cmake_install.cmake | 0 libs/snake_old/test/test_snake.cpp | 334 + libs/snake_old/test/test_snake_geometry.cpp | 663 + qgroundcontrol.pro | 35 +- .../Airmap_autogen/mocs_compilation.cpp | 2 + .../AnalyzeView_autogen/mocs_compilation.cpp | 5 + src/Audio/Audio_autogen/mocs_compilation.cpp | 3 + .../mocs_compilation.cpp | 42 + .../Camera_autogen/mocs_compilation.cpp | 3 + .../FactSystem_autogen/mocs_compilation.cpp | 13 + .../mocs_compilation.cpp | 14 + src/FlightDisplay/FlightDisplayWimaMenu.qml | 30 + .../mocs_compilation.cpp | 2 + .../FlightMap_autogen/mocs_compilation.cpp | 2 + .../FollowMe_autogen/mocs_compilation.cpp | 2 + src/GPS/gps_autogen/mocs_compilation.cpp | 4 + .../Joystick_autogen/mocs_compilation.cpp | 3 + .../mocs_compilation.cpp | 53 + .../mocs_compilation.cpp | 3 + .../QmlControls_autogen/mocs_compilation.cpp | 12 + .../mocs_compilation.cpp | 13 + .../Settings_autogen/mocs_compilation.cpp | 14 + src/Snake/clipper/clipper.cpp | 4629 ++++ src/Snake/clipper/clipper.hpp | 406 + src/Snake/mapbox/feature.hpp | 113 + src/Snake/mapbox/geometry.hpp | 12 + src/Snake/mapbox/geometry/box.hpp | 36 + src/Snake/mapbox/geometry/empty.hpp | 18 + src/Snake/mapbox/geometry/envelope.hpp | 33 + src/Snake/mapbox/geometry/for_each_point.hpp | 51 + src/Snake/mapbox/geometry/geometry.hpp | 56 + src/Snake/mapbox/geometry/line_string.hpp | 28 + .../mapbox/geometry/multi_line_string.hpp | 28 + src/Snake/mapbox/geometry/multi_point.hpp | 28 + src/Snake/mapbox/geometry/multi_polygon.hpp | 28 + src/Snake/mapbox/geometry/point.hpp | 42 + .../mapbox/geometry/point_arithmetic.hpp | 119 + src/Snake/mapbox/geometry/polygon.hpp | 45 + src/Snake/mapbox/geometry_io.hpp | 98 + src/Snake/mapbox/optional.hpp | 74 + src/Snake/mapbox/polylabel.hpp | 178 + src/Snake/mapbox/recursive_wrapper.hpp | 122 + src/Snake/mapbox/variant.hpp | 901 + src/Snake/mapbox/variant_io.hpp | 45 + src/Snake/snake.cpp | 608 + src/Snake/snake.h | 147 + src/Snake/snake_geometry.cpp | 451 + src/Snake/snake_geometry.h | 136 + src/Snake/snake_global.h | 18 + .../Terrain_autogen/mocs_compilation.cpp | 2 + .../Vehicle_autogen/mocs_compilation.cpp | 7 + .../VehicleSetup_autogen/mocs_compilation.cpp | 7 + .../mocs_compilation.cpp | 4 + .../ViewWidgets_autogen/mocs_compilation.cpp | 4 + src/Wima/WimaController.SettingsGroup.json | 35 + src/Wima/WimaController.cc | 242 +- src/Wima/WimaController.h | 106 +- src/Wima/WimaControllerDetail.cc | 79 + src/Wima/WimaControllerDetail.h | 49 + src/api/api_autogen/mocs_compilation.cpp | 5 + src/comm/comm_autogen/mocs_compilation.cpp | 18 + src/comm/utilities.h | 70 + src/qgc_autogen/mocs_compilation.cpp | 18 + .../qgcunittest_autogen/mocs_compilation.cpp | 14 + src/uas/uas_autogen/mocs_compilation.cpp | 5 + 150 files changed, 36735 insertions(+), 5908 deletions(-) delete mode 100644 libs/clipper/CMakeLists.txt delete mode 100644 libs/clipper/Makefile create mode 100644 libs/clipper/clipper/.gitignore rename libs/clipper/{ => clipper}/clipper.cpp (92%) rename libs/clipper/{include => clipper}/clipper.hpp (95%) create mode 100644 libs/clipper/clipper/clipper.pro create mode 100644 libs/clipper/clipper/clipper_global.h delete mode 100644 libs/clipper/cmake_install.cmake create mode 100644 libs/qwt/qwt_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/dbfadd create mode 100644 libs/shapelib/dbfadd_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/dbfcreate create mode 100644 libs/shapelib/dbfcreate_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/dbfdump create mode 100644 libs/shapelib/dbfdump_autogen/mocs_compilation.cpp create mode 100644 libs/shapelib/shp_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/shpadd create mode 100644 libs/shapelib/shpadd_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/shpcreate create mode 100644 libs/shapelib/shpcreate_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/shpdump create mode 100644 libs/shapelib/shpdump_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/shprewind create mode 100644 libs/shapelib/shprewind_autogen/mocs_compilation.cpp create mode 100755 libs/shapelib/shptreedump create mode 100644 libs/shapelib/shptreedump_autogen/mocs_compilation.cpp create mode 100644 libs/snake/.gitignore delete mode 100644 libs/snake/CMakeLists.txt delete mode 100644 libs/snake/Makefile delete mode 100644 libs/snake/cmake_install.cmake rename libs/snake/{polylabel => }/mapbox/feature.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/box.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/empty.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/envelope.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/for_each_point.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/geometry.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/line_string.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/multi_line_string.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/multi_point.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/multi_polygon.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/point.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/point_arithmetic.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry/polygon.hpp (100%) rename libs/snake/{polylabel => }/mapbox/geometry_io.hpp (100%) rename libs/snake/{polylabel => }/mapbox/optional.hpp (100%) rename libs/snake/{polylabel/mapbox/polylabel => mapbox}/polylabel.hpp (100%) rename libs/snake/{polylabel => }/mapbox/recursive_wrapper.hpp (100%) rename libs/snake/{polylabel => }/mapbox/variant.hpp (100%) rename libs/snake/{polylabel => }/mapbox/variant_io.hpp (100%) rename libs/snake/{include => }/snake.h (100%) create mode 100644 libs/snake/snake.pro rename libs/snake/{include => }/snake_geometry.h (100%) delete mode 100644 libs/snake/snake_geometry.h.orig create mode 100644 libs/snake/snake_global.h create mode 100644 libs/snake_old/catch.hpp create mode 100644 libs/snake_old/polylabel/mapbox/feature.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/box.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/empty.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/envelope.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/for_each_point.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/geometry.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/line_string.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/multi_line_string.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/multi_point.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/multi_polygon.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/point.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/point_arithmetic.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry/polygon.hpp create mode 100644 libs/snake_old/polylabel/mapbox/geometry_io.hpp create mode 100644 libs/snake_old/polylabel/mapbox/optional.hpp create mode 100644 libs/snake_old/polylabel/mapbox/polylabel/polylabel.hpp create mode 100644 libs/snake_old/polylabel/mapbox/recursive_wrapper.hpp create mode 100644 libs/snake_old/polylabel/mapbox/variant.hpp create mode 100644 libs/snake_old/polylabel/mapbox/variant_io.hpp create mode 100644 libs/snake_old/snake.cpp create mode 100644 libs/snake_old/snake.h create mode 100644 libs/snake_old/snake_geometry.cpp create mode 100644 libs/snake_old/snake_geometry.h rename libs/{snake => snake_old}/test/CMakeLists.txt (100%) rename libs/{snake => snake_old}/test/Makefile (100%) rename libs/{snake => snake_old}/test/cmake_install.cmake (100%) create mode 100644 libs/snake_old/test/test_snake.cpp create mode 100644 libs/snake_old/test/test_snake_geometry.cpp create mode 100644 src/Airmap/Airmap_autogen/mocs_compilation.cpp create mode 100644 src/AnalyzeView/AnalyzeView_autogen/mocs_compilation.cpp create mode 100644 src/Audio/Audio_autogen/mocs_compilation.cpp create mode 100644 src/AutoPilotPlugins/AutoPilotPlugins_autogen/mocs_compilation.cpp create mode 100644 src/Camera/Camera_autogen/mocs_compilation.cpp create mode 100644 src/FactSystem/FactSystem_autogen/mocs_compilation.cpp create mode 100644 src/FirmwarePlugin/FirmwarePlugin_autogen/mocs_compilation.cpp create mode 100644 src/FlightDisplay/FlightDisplay_autogen/mocs_compilation.cpp create mode 100644 src/FlightMap/FlightMap_autogen/mocs_compilation.cpp create mode 100644 src/FollowMe/FollowMe_autogen/mocs_compilation.cpp create mode 100644 src/GPS/gps_autogen/mocs_compilation.cpp create mode 100644 src/Joystick/Joystick_autogen/mocs_compilation.cpp create mode 100644 src/MissionManager/MissionManager_autogen/mocs_compilation.cpp create mode 100644 src/PositionManager/PositionManager_autogen/mocs_compilation.cpp create mode 100644 src/QmlControls/QmlControls_autogen/mocs_compilation.cpp create mode 100644 src/QtLocationPlugin/QtLocationPlugin_autogen/mocs_compilation.cpp create mode 100644 src/Settings/Settings_autogen/mocs_compilation.cpp create mode 100644 src/Snake/clipper/clipper.cpp create mode 100644 src/Snake/clipper/clipper.hpp create mode 100644 src/Snake/mapbox/feature.hpp create mode 100644 src/Snake/mapbox/geometry.hpp create mode 100644 src/Snake/mapbox/geometry/box.hpp create mode 100644 src/Snake/mapbox/geometry/empty.hpp create mode 100644 src/Snake/mapbox/geometry/envelope.hpp create mode 100644 src/Snake/mapbox/geometry/for_each_point.hpp create mode 100644 src/Snake/mapbox/geometry/geometry.hpp create mode 100644 src/Snake/mapbox/geometry/line_string.hpp create mode 100644 src/Snake/mapbox/geometry/multi_line_string.hpp create mode 100644 src/Snake/mapbox/geometry/multi_point.hpp create mode 100644 src/Snake/mapbox/geometry/multi_polygon.hpp create mode 100644 src/Snake/mapbox/geometry/point.hpp create mode 100644 src/Snake/mapbox/geometry/point_arithmetic.hpp create mode 100644 src/Snake/mapbox/geometry/polygon.hpp create mode 100644 src/Snake/mapbox/geometry_io.hpp create mode 100644 src/Snake/mapbox/optional.hpp create mode 100644 src/Snake/mapbox/polylabel.hpp create mode 100644 src/Snake/mapbox/recursive_wrapper.hpp create mode 100644 src/Snake/mapbox/variant.hpp create mode 100644 src/Snake/mapbox/variant_io.hpp create mode 100644 src/Snake/snake.cpp create mode 100644 src/Snake/snake.h create mode 100644 src/Snake/snake_geometry.cpp create mode 100644 src/Snake/snake_geometry.h create mode 100644 src/Snake/snake_global.h create mode 100644 src/Terrain/Terrain_autogen/mocs_compilation.cpp create mode 100644 src/Vehicle/Vehicle_autogen/mocs_compilation.cpp create mode 100644 src/VehicleSetup/VehicleSetup_autogen/mocs_compilation.cpp create mode 100644 src/VideoStreaming/VideoStreaming_autogen/mocs_compilation.cpp create mode 100644 src/ViewWidgets/ViewWidgets_autogen/mocs_compilation.cpp create mode 100644 src/Wima/WimaControllerDetail.cc create mode 100644 src/Wima/WimaControllerDetail.h create mode 100644 src/api/api_autogen/mocs_compilation.cpp create mode 100644 src/comm/comm_autogen/mocs_compilation.cpp create mode 100644 src/comm/utilities.h create mode 100644 src/qgc_autogen/mocs_compilation.cpp create mode 100644 src/qgcunittest/qgcunittest_autogen/mocs_compilation.cpp create mode 100644 src/uas/uas_autogen/mocs_compilation.cpp diff --git a/QGCExternalLibs.pri b/QGCExternalLibs.pri index 70fa4595f..e1dbf021c 100644 --- a/QGCExternalLibs.pri +++ b/QGCExternalLibs.pri @@ -92,11 +92,6 @@ exists($$MAVLINKPATH/common) { INCLUDEPATH += libs/eigen DEFINES += NOMINMAX -# -# [REQUIRED] snake library (Wima) -INCLUDEPATH += libs/snake -INCLUDEPATH += libs/or-tools/include - # # [REQUIRED] shapelib library INCLUDEPATH += libs/shapelib @@ -200,3 +195,13 @@ contains (DEFINES, DISABLE_AIRMAP) { $${AIRMAPD_PATH}/include } } + +# GeograpicLib (TODO: add Windows support!) +LinuxBuild { + LIBS += -L/usr/local/lib -lGeographic # libGeograpic.so +} + +# google or-tools (TODO: add Windows support!) +LinuxBuild { + LIBS += -L/usr/local/lib -lortools # libortools.so +} diff --git a/libs/clipper/CMakeLists.txt b/libs/clipper/CMakeLists.txt deleted file mode 100644 index af3d7b694..000000000 --- a/libs/clipper/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(polyclipping) - - -add_library(polyclipping - STATIC - clipper.cpp) -target_include_directories(polyclipping PUBLIC include) diff --git a/libs/clipper/Makefile b/libs/clipper/Makefile deleted file mode 100644 index b83cf1077..000000000 --- a/libs/clipper/Makefile +++ /dev/null @@ -1,296 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.18 - -# Default target executed when no arguments are given to make. -default_target: all - -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - - -# Disable VCS-based implicit rules. -% : %,v - - -# Disable VCS-based implicit rules. -% : RCS/% - - -# Disable VCS-based implicit rules. -% : RCS/%,v - - -# Disable VCS-based implicit rules. -% : SCCS/s.% - - -# Disable VCS-based implicit rules. -% : s.% - - -.SUFFIXES: .hpux_make_needs_suffix_list - - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -# Suppress display of executed commands. -$$(VERBOSE).SILENT: - - -# A target that is always out of date. -cmake_force: - -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /usr/local/bin/cmake - -# The command to remove a file. -RM = /usr/local/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/valentin/Desktop/drones/qgroundcontrol - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/valentin/Desktop/drones/qgroundcontrol - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target install/strip -install/strip: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip - -# Special rule for the target install/strip -install/strip/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." - /usr/local/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache - -.PHONY : edit_cache/fast - -# Special rule for the target install -install: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /usr/local/bin/cmake -P cmake_install.cmake -.PHONY : install - -# Special rule for the target install -install/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /usr/local/bin/cmake -P cmake_install.cmake -.PHONY : install/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." - /usr/local/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache - -.PHONY : rebuild_cache/fast - -# Special rule for the target list_install_components -list_install_components: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" -.PHONY : list_install_components - -# Special rule for the target list_install_components -list_install_components/fast: list_install_components - -.PHONY : list_install_components/fast - -# Special rule for the target install/local -install/local: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local - -# Special rule for the target install/local -install/local/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local/fast - -# The main all target -all: cmake_check_build_system - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -E cmake_progress_start /home/valentin/Desktop/drones/qgroundcontrol/CMakeFiles /home/valentin/Desktop/drones/qgroundcontrol/libs/clipper//CMakeFiles/progress.marks - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/all - $(CMAKE_COMMAND) -E cmake_progress_start /home/valentin/Desktop/drones/qgroundcontrol/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/clean -.PHONY : clean - -# The main clean target -clean/fast: clean - -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -# Convenience name for target. -libs/clipper/CMakeFiles/polyclipping.dir/rule: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/CMakeFiles/polyclipping.dir/rule -.PHONY : libs/clipper/CMakeFiles/polyclipping.dir/rule - -# Convenience name for target. -polyclipping: libs/clipper/CMakeFiles/polyclipping.dir/rule - -.PHONY : polyclipping - -# fast build rule for target. -polyclipping/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/build -.PHONY : polyclipping/fast - -# Convenience name for target. -libs/clipper/CMakeFiles/polyclipping_autogen.dir/rule: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/clipper/CMakeFiles/polyclipping_autogen.dir/rule -.PHONY : libs/clipper/CMakeFiles/polyclipping_autogen.dir/rule - -# Convenience name for target. -polyclipping_autogen: libs/clipper/CMakeFiles/polyclipping_autogen.dir/rule - -.PHONY : polyclipping_autogen - -# fast build rule for target. -polyclipping_autogen/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping_autogen.dir/build.make libs/clipper/CMakeFiles/polyclipping_autogen.dir/build -.PHONY : polyclipping_autogen/fast - -clipper.o: clipper.cpp.o - -.PHONY : clipper.o - -# target to build an object file -clipper.cpp.o: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/clipper.cpp.o -.PHONY : clipper.cpp.o - -clipper.i: clipper.cpp.i - -.PHONY : clipper.i - -# target to preprocess a source file -clipper.cpp.i: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/clipper.cpp.i -.PHONY : clipper.cpp.i - -clipper.s: clipper.cpp.s - -.PHONY : clipper.s - -# target to generate assembly for a file -clipper.cpp.s: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/clipper.cpp.s -.PHONY : clipper.cpp.s - -polyclipping_autogen/mocs_compilation.o: polyclipping_autogen/mocs_compilation.cpp.o - -.PHONY : polyclipping_autogen/mocs_compilation.o - -# target to build an object file -polyclipping_autogen/mocs_compilation.cpp.o: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/polyclipping_autogen/mocs_compilation.cpp.o -.PHONY : polyclipping_autogen/mocs_compilation.cpp.o - -polyclipping_autogen/mocs_compilation.i: polyclipping_autogen/mocs_compilation.cpp.i - -.PHONY : polyclipping_autogen/mocs_compilation.i - -# target to preprocess a source file -polyclipping_autogen/mocs_compilation.cpp.i: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/polyclipping_autogen/mocs_compilation.cpp.i -.PHONY : polyclipping_autogen/mocs_compilation.cpp.i - -polyclipping_autogen/mocs_compilation.s: polyclipping_autogen/mocs_compilation.cpp.s - -.PHONY : polyclipping_autogen/mocs_compilation.s - -# target to generate assembly for a file -polyclipping_autogen/mocs_compilation.cpp.s: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/clipper/CMakeFiles/polyclipping.dir/build.make libs/clipper/CMakeFiles/polyclipping.dir/polyclipping_autogen/mocs_compilation.cpp.s -.PHONY : polyclipping_autogen/mocs_compilation.cpp.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... edit_cache" - @echo "... install" - @echo "... install/local" - @echo "... install/strip" - @echo "... list_install_components" - @echo "... rebuild_cache" - @echo "... polyclipping_autogen" - @echo "... polyclipping" - @echo "... clipper.o" - @echo "... clipper.i" - @echo "... clipper.s" - @echo "... polyclipping_autogen/mocs_compilation.o" - @echo "... polyclipping_autogen/mocs_compilation.i" - @echo "... polyclipping_autogen/mocs_compilation.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - diff --git a/libs/clipper/clipper/.gitignore b/libs/clipper/clipper/.gitignore new file mode 100644 index 000000000..fab7372d7 --- /dev/null +++ b/libs/clipper/clipper/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/libs/clipper/clipper.cpp b/libs/clipper/clipper/clipper.cpp similarity index 92% rename from libs/clipper/clipper.cpp rename to libs/clipper/clipper/clipper.cpp index d0e5ba257..65affb876 100644 --- a/libs/clipper/clipper.cpp +++ b/libs/clipper/clipper/clipper.cpp @@ -1,4629 +1,4629 @@ -/******************************************************************************* -* * -* Author : Angus Johnson * -* Version : 6.4.2 * -* Date : 27 February 2017 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2017 * -* * -* License: * -* Use, modification & distribution is subject to Boost Software License Ver 1. * -* http://www.boost.org/LICENSE_1_0.txt * -* * -* Attributions: * -* The code in this library is an extension of Bala Vatti's clipping algorithm: * -* "A generic solution to polygon clipping" * -* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * -* http://portal.acm.org/citation.cfm?id=129906 * -* * -* Computer graphics and geometric modeling: implementation and algorithms * -* By Max K. Agoston * -* Springer; 1 edition (January 4, 2005) * -* http://books.google.com/books?q=vatti+clipping+agoston * -* * -* See also: * -* "Polygon Offsetting by Computing Winding Numbers" * -* Paper no. DETC2005-85513 pp. 565-575 * -* ASME 2005 International Design Engineering Technical Conferences * -* and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24-28, 2005 , Long Beach, California, USA * -* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * -* * -*******************************************************************************/ - -/******************************************************************************* -* * -* This is a translation of the Delphi Clipper library and the naming style * -* used has retained a Delphi flavour. * -* * -*******************************************************************************/ - -#include "clipper.hpp" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ClipperLib { - -static double const pi = 3.141592653589793238; -static double const two_pi = pi *2; -static double const def_arc_tolerance = 0.25; - -enum Direction { dRightToLeft, dLeftToRight }; - -static int const Unassigned = -1; //edge not currently 'owning' a solution -static int const Skip = -2; //edge that would otherwise close a path - -#define HORIZONTAL (-1.0E+40) -#define TOLERANCE (1.0e-20) -#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) - -struct TEdge { - IntPoint Bot; - IntPoint Curr; //current (updated for every new scanbeam) - IntPoint Top; - double Dx; - PolyType PolyTyp; - EdgeSide Side; //side only refers to current side of solution poly - int WindDelta; //1 or -1 depending on winding direction - int WindCnt; - int WindCnt2; //winding count of the opposite polytype - int OutIdx; - TEdge *Next; - TEdge *Prev; - TEdge *NextInLML; - TEdge *NextInAEL; - TEdge *PrevInAEL; - TEdge *NextInSEL; - TEdge *PrevInSEL; -}; - -struct IntersectNode { - TEdge *Edge1; - TEdge *Edge2; - IntPoint Pt; -}; - -struct LocalMinimum { - cInt Y; - TEdge *LeftBound; - TEdge *RightBound; -}; - -struct OutPt; - -//OutRec: contains a path in the clipping solution. Edges in the AEL will -//carry a pointer to an OutRec when they are part of the clipping solution. -struct OutRec { - int Idx; - bool IsHole; - bool IsOpen; - OutRec *FirstLeft; //see comments in clipper.pas - PolyNode *PolyNd; - OutPt *Pts; - OutPt *BottomPt; -}; - -struct OutPt { - int Idx; - IntPoint Pt; - OutPt *Next; - OutPt *Prev; -}; - -struct Join { - OutPt *OutPt1; - OutPt *OutPt2; - IntPoint OffPt; -}; - -struct LocMinSorter -{ - inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2) - { - return locMin2.Y < locMin1.Y; - } -}; - -//------------------------------------------------------------------------------ -//------------------------------------------------------------------------------ - -inline cInt Round(double val) -{ - if ((val < 0)) return static_cast(val - 0.5); - else return static_cast(val + 0.5); -} -//------------------------------------------------------------------------------ - -inline cInt Abs(cInt val) -{ - return val < 0 ? -val : val; -} - -//------------------------------------------------------------------------------ -// PolyTree methods ... -//------------------------------------------------------------------------------ - -void PolyTree::Clear() -{ - for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) - delete AllNodes[i]; - AllNodes.resize(0); - Childs.resize(0); -} -//------------------------------------------------------------------------------ - -PolyNode* PolyTree::GetFirst() const -{ - if (!Childs.empty()) - return Childs[0]; - else - return 0; -} -//------------------------------------------------------------------------------ - -int PolyTree::Total() const -{ - int result = (int)AllNodes.size(); - //with negative offsets, ignore the hidden outer polygon ... - if (result > 0 && Childs[0] != AllNodes[0]) result--; - return result; -} - -//------------------------------------------------------------------------------ -// PolyNode methods ... -//------------------------------------------------------------------------------ - -PolyNode::PolyNode(): Parent(0), Index(0), m_IsOpen(false) -{ -} -//------------------------------------------------------------------------------ - -int PolyNode::ChildCount() const -{ - return (int)Childs.size(); -} -//------------------------------------------------------------------------------ - -void PolyNode::AddChild(PolyNode& child) -{ - unsigned cnt = (unsigned)Childs.size(); - Childs.push_back(&child); - child.Parent = this; - child.Index = cnt; -} -//------------------------------------------------------------------------------ - -PolyNode* PolyNode::GetNext() const -{ - if (!Childs.empty()) - return Childs[0]; - else - return GetNextSiblingUp(); -} -//------------------------------------------------------------------------------ - -PolyNode* PolyNode::GetNextSiblingUp() const -{ - if (!Parent) //protects against PolyTree.GetNextSiblingUp() - return 0; - else if (Index == Parent->Childs.size() - 1) - return Parent->GetNextSiblingUp(); - else - return Parent->Childs[Index + 1]; -} -//------------------------------------------------------------------------------ - -bool PolyNode::IsHole() const -{ - bool result = true; - PolyNode* node = Parent; - while (node) - { - result = !result; - node = node->Parent; - } - return result; -} -//------------------------------------------------------------------------------ - -bool PolyNode::IsOpen() const -{ - return m_IsOpen; -} -//------------------------------------------------------------------------------ - -#ifndef use_int32 - -//------------------------------------------------------------------------------ -// Int128 class (enables safe math on signed 64bit integers) -// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 -// Int128 val2((long64)9223372036854775807); -// Int128 val3 = val1 * val2; -// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) -//------------------------------------------------------------------------------ - -class Int128 -{ - public: - ulong64 lo; - long64 hi; - - Int128(long64 _lo = 0) - { - lo = (ulong64)_lo; - if (_lo < 0) hi = -1; else hi = 0; - } - - - Int128(const Int128 &val): lo(val.lo), hi(val.hi){} - - Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} - - Int128& operator = (const long64 &val) - { - lo = (ulong64)val; - if (val < 0) hi = -1; else hi = 0; - return *this; - } - - bool operator == (const Int128 &val) const - {return (hi == val.hi && lo == val.lo);} - - bool operator != (const Int128 &val) const - { return !(*this == val);} - - bool operator > (const Int128 &val) const - { - if (hi != val.hi) - return hi > val.hi; - else - return lo > val.lo; - } - - bool operator < (const Int128 &val) const - { - if (hi != val.hi) - return hi < val.hi; - else - return lo < val.lo; - } - - bool operator >= (const Int128 &val) const - { return !(*this < val);} - - bool operator <= (const Int128 &val) const - { return !(*this > val);} - - Int128& operator += (const Int128 &rhs) - { - hi += rhs.hi; - lo += rhs.lo; - if (lo < rhs.lo) hi++; - return *this; - } - - Int128 operator + (const Int128 &rhs) const - { - Int128 result(*this); - result+= rhs; - return result; - } - - Int128& operator -= (const Int128 &rhs) - { - *this += -rhs; - return *this; - } - - Int128 operator - (const Int128 &rhs) const - { - Int128 result(*this); - result -= rhs; - return result; - } - - Int128 operator-() const //unary negation - { - if (lo == 0) - return Int128(-hi, 0); - else - return Int128(~hi, ~lo + 1); - } - - operator double() const - { - const double shift64 = 18446744073709551616.0; //2^64 - if (hi < 0) - { - if (lo == 0) return (double)hi * shift64; - else return -(double)(~lo + ~hi * shift64); - } - else - return (double)(lo + hi * shift64); - } - -}; -//------------------------------------------------------------------------------ - -Int128 Int128Mul (long64 lhs, long64 rhs) -{ - bool negate = (lhs < 0) != (rhs < 0); - - if (lhs < 0) lhs = -lhs; - ulong64 int1Hi = ulong64(lhs) >> 32; - ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); - - if (rhs < 0) rhs = -rhs; - ulong64 int2Hi = ulong64(rhs) >> 32; - ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); - - //nb: see comments in clipper.pas - ulong64 a = int1Hi * int2Hi; - ulong64 b = int1Lo * int2Lo; - ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; - - Int128 tmp; - tmp.hi = long64(a + (c >> 32)); - tmp.lo = long64(c << 32); - tmp.lo += long64(b); - if (tmp.lo < b) tmp.hi++; - if (negate) tmp = -tmp; - return tmp; -}; -#endif - -//------------------------------------------------------------------------------ -// Miscellaneous global functions -//------------------------------------------------------------------------------ - -bool Orientation(const Path &poly) -{ - return Area(poly) >= 0; -} -//------------------------------------------------------------------------------ - -double Area(const Path &poly) -{ - int size = (int)poly.size(); - if (size < 3) return 0; - - double a = 0; - for (int i = 0, j = size -1; i < size; ++i) - { - a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); - j = i; - } - return -a * 0.5; -} -//------------------------------------------------------------------------------ - -double Area(const OutPt *op) -{ - const OutPt *startOp = op; - if (!op) return 0; - double a = 0; - do { - a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y); - op = op->Next; - } while (op != startOp); - return a * 0.5; -} -//------------------------------------------------------------------------------ - -double Area(const OutRec &outRec) -{ - return Area(outRec.Pts); -} -//------------------------------------------------------------------------------ - -bool PointIsVertex(const IntPoint &Pt, OutPt *pp) -{ - OutPt *pp2 = pp; - do - { - if (pp2->Pt == Pt) return true; - pp2 = pp2->Next; - } - while (pp2 != pp); - return false; -} -//------------------------------------------------------------------------------ - -//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos -//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf -int PointInPolygon(const IntPoint &pt, const Path &path) -{ - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - size_t cnt = path.size(); - if (cnt < 3) return 0; - IntPoint ip = path[0]; - for(size_t i = 1; i <= cnt; ++i) - { - IntPoint ipNext = (i == cnt ? path[0] : path[i]); - if (ipNext.Y == pt.Y) - { - if ((ipNext.X == pt.X) || (ip.Y == pt.Y && - ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; - } - if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) - { - if (ip.X >= pt.X) - { - if (ipNext.X > pt.X) result = 1 - result; - else - { - double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); - if (!d) return -1; - if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; - } - } else - { - if (ipNext.X > pt.X) - { - double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - - (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); - if (!d) return -1; - if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; - } - } - } - ip = ipNext; - } - return result; -} -//------------------------------------------------------------------------------ - -int PointInPolygon (const IntPoint &pt, OutPt *op) -{ - //returns 0 if false, +1 if true, -1 if pt ON polygon boundary - int result = 0; - OutPt* startOp = op; - for(;;) - { - if (op->Next->Pt.Y == pt.Y) - { - if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y && - ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1; - } - if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) - { - if (op->Pt.X >= pt.X) - { - if (op->Next->Pt.X > pt.X) result = 1 - result; - else - { - double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); - if (!d) return -1; - if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; - } - } else - { - if (op->Next->Pt.X > pt.X) - { - double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - - (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); - if (!d) return -1; - if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; - } - } - } - op = op->Next; - if (startOp == op) break; - } - return result; -} -//------------------------------------------------------------------------------ - -bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) -{ - OutPt* op = OutPt1; - do - { - //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon - int res = PointInPolygon(op->Pt, OutPt2); - if (res >= 0) return res > 0; - op = op->Next; - } - while (op != OutPt1); - return true; -} -//---------------------------------------------------------------------- - -bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) -{ -#ifndef use_int32 - if (UseFullInt64Range) - return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) == - Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y); - else -#endif - return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) == - (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y); -} -//------------------------------------------------------------------------------ - -bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, - const IntPoint pt3, bool UseFullInt64Range) -{ -#ifndef use_int32 - if (UseFullInt64Range) - return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); - else -#endif - return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); -} -//------------------------------------------------------------------------------ - -bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, - const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) -{ -#ifndef use_int32 - if (UseFullInt64Range) - return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); - else -#endif - return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); -} -//------------------------------------------------------------------------------ - -inline bool IsHorizontal(TEdge &e) -{ - return e.Dx == HORIZONTAL; -} -//------------------------------------------------------------------------------ - -inline double GetDx(const IntPoint pt1, const IntPoint pt2) -{ - return (pt1.Y == pt2.Y) ? - HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); -} -//--------------------------------------------------------------------------- - -inline void SetDx(TEdge &e) -{ - cInt dy = (e.Top.Y - e.Bot.Y); - if (dy == 0) e.Dx = HORIZONTAL; - else e.Dx = (double)(e.Top.X - e.Bot.X) / dy; -} -//--------------------------------------------------------------------------- - -inline void SwapSides(TEdge &Edge1, TEdge &Edge2) -{ - EdgeSide Side = Edge1.Side; - Edge1.Side = Edge2.Side; - Edge2.Side = Side; -} -//------------------------------------------------------------------------------ - -inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) -{ - int OutIdx = Edge1.OutIdx; - Edge1.OutIdx = Edge2.OutIdx; - Edge2.OutIdx = OutIdx; -} -//------------------------------------------------------------------------------ - -inline cInt TopX(TEdge &edge, const cInt currentY) -{ - return ( currentY == edge.Top.Y ) ? - edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); -} -//------------------------------------------------------------------------------ - -void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) -{ -#ifdef use_xyz - ip.Z = 0; -#endif - - double b1, b2; - if (Edge1.Dx == Edge2.Dx) - { - ip.Y = Edge1.Curr.Y; - ip.X = TopX(Edge1, ip.Y); - return; - } - else if (Edge1.Dx == 0) - { - ip.X = Edge1.Bot.X; - if (IsHorizontal(Edge2)) - ip.Y = Edge2.Bot.Y; - else - { - b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx); - ip.Y = Round(ip.X / Edge2.Dx + b2); - } - } - else if (Edge2.Dx == 0) - { - ip.X = Edge2.Bot.X; - if (IsHorizontal(Edge1)) - ip.Y = Edge1.Bot.Y; - else - { - b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx); - ip.Y = Round(ip.X / Edge1.Dx + b1); - } - } - else - { - b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx; - b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; - double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); - ip.Y = Round(q); - if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) - ip.X = Round(Edge1.Dx * q + b1); - else - ip.X = Round(Edge2.Dx * q + b2); - } - - if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) - { - if (Edge1.Top.Y > Edge2.Top.Y) - ip.Y = Edge1.Top.Y; - else - ip.Y = Edge2.Top.Y; - if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) - ip.X = TopX(Edge1, ip.Y); - else - ip.X = TopX(Edge2, ip.Y); - } - //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ... - if (ip.Y > Edge1.Curr.Y) - { - ip.Y = Edge1.Curr.Y; - //use the more vertical edge to derive X ... - if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx)) - ip.X = TopX(Edge2, ip.Y); else - ip.X = TopX(Edge1, ip.Y); - } -} -//------------------------------------------------------------------------------ - -void ReversePolyPtLinks(OutPt *pp) -{ - if (!pp) return; - OutPt *pp1, *pp2; - pp1 = pp; - do { - pp2 = pp1->Next; - pp1->Next = pp1->Prev; - pp1->Prev = pp2; - pp1 = pp2; - } while( pp1 != pp ); -} -//------------------------------------------------------------------------------ - -void DisposeOutPts(OutPt*& pp) -{ - if (pp == 0) return; - pp->Prev->Next = 0; - while( pp ) - { - OutPt *tmpPp = pp; - pp = pp->Next; - delete tmpPp; - } -} -//------------------------------------------------------------------------------ - -inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) -{ - std::memset(e, 0, sizeof(TEdge)); - e->Next = eNext; - e->Prev = ePrev; - e->Curr = Pt; - e->OutIdx = Unassigned; -} -//------------------------------------------------------------------------------ - -void InitEdge2(TEdge& e, PolyType Pt) -{ - if (e.Curr.Y >= e.Next->Curr.Y) - { - e.Bot = e.Curr; - e.Top = e.Next->Curr; - } else - { - e.Top = e.Curr; - e.Bot = e.Next->Curr; - } - SetDx(e); - e.PolyTyp = Pt; -} -//------------------------------------------------------------------------------ - -TEdge* RemoveEdge(TEdge* e) -{ - //removes e from double_linked_list (but without removing from memory) - e->Prev->Next = e->Next; - e->Next->Prev = e->Prev; - TEdge* result = e->Next; - e->Prev = 0; //flag as removed (see ClipperBase.Clear) - return result; -} -//------------------------------------------------------------------------------ - -inline void ReverseHorizontal(TEdge &e) -{ - //swap horizontal edges' Top and Bottom x's so they follow the natural - //progression of the bounds - ie so their xbots will align with the - //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] - std::swap(e.Top.X, e.Bot.X); -#ifdef use_xyz - std::swap(e.Top.Z, e.Bot.Z); -#endif -} -//------------------------------------------------------------------------------ - -void SwapPoints(IntPoint &pt1, IntPoint &pt2) -{ - IntPoint tmp = pt1; - pt1 = pt2; - pt2 = tmp; -} -//------------------------------------------------------------------------------ - -bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, - IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) -{ - //precondition: segments are Collinear. - if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) - { - if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); - if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); - if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; - if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; - return pt1.X < pt2.X; - } else - { - if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); - if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); - if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; - if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; - return pt1.Y > pt2.Y; - } -} -//------------------------------------------------------------------------------ - -bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) -{ - OutPt *p = btmPt1->Prev; - while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; - double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); - p = btmPt1->Next; - while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; - double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); - - p = btmPt2->Prev; - while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; - double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); - p = btmPt2->Next; - while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; - double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); - - if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) && - std::min(dx1p, dx1n) == std::min(dx2p, dx2n)) - return Area(btmPt1) > 0; //if otherwise identical use orientation - else - return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); -} -//------------------------------------------------------------------------------ - -OutPt* GetBottomPt(OutPt *pp) -{ - OutPt* dups = 0; - OutPt* p = pp->Next; - while (p != pp) - { - if (p->Pt.Y > pp->Pt.Y) - { - pp = p; - dups = 0; - } - else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) - { - if (p->Pt.X < pp->Pt.X) - { - dups = 0; - pp = p; - } else - { - if (p->Next != pp && p->Prev != pp) dups = p; - } - } - p = p->Next; - } - if (dups) - { - //there appears to be at least 2 vertices at BottomPt so ... - while (dups != p) - { - if (!FirstIsBottomPt(p, dups)) pp = dups; - dups = dups->Next; - while (dups->Pt != pp->Pt) dups = dups->Next; - } - } - return pp; -} -//------------------------------------------------------------------------------ - -bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, - const IntPoint pt2, const IntPoint pt3) -{ - if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) - return false; - else if (pt1.X != pt3.X) - return (pt2.X > pt1.X) == (pt2.X < pt3.X); - else - return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); -} -//------------------------------------------------------------------------------ - -bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) -{ - if (seg1a > seg1b) std::swap(seg1a, seg1b); - if (seg2a > seg2b) std::swap(seg2a, seg2b); - return (seg1a < seg2b) && (seg2a < seg1b); -} - -//------------------------------------------------------------------------------ -// ClipperBase class methods ... -//------------------------------------------------------------------------------ - -ClipperBase::ClipperBase() //constructor -{ - m_CurrentLM = m_MinimaList.begin(); //begin() == end() here - m_UseFullRange = false; -} -//------------------------------------------------------------------------------ - -ClipperBase::~ClipperBase() //destructor -{ - Clear(); -} -//------------------------------------------------------------------------------ - -void RangeTest(const IntPoint& Pt, bool& useFullRange) -{ - if (useFullRange) - { - if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) - throw clipperException("Coordinate outside allowed range"); - } - else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) - { - useFullRange = true; - RangeTest(Pt, useFullRange); - } -} -//------------------------------------------------------------------------------ - -TEdge* FindNextLocMin(TEdge* E) -{ - for (;;) - { - while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; - if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; - while (IsHorizontal(*E->Prev)) E = E->Prev; - TEdge* E2 = E; - while (IsHorizontal(*E)) E = E->Next; - if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz. - if (E2->Prev->Bot.X < E->Bot.X) E = E2; - break; - } - return E; -} -//------------------------------------------------------------------------------ - -TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward) -{ - TEdge *Result = E; - TEdge *Horz = 0; - - if (E->OutIdx == Skip) - { - //if edges still remain in the current bound beyond the skip edge then - //create another LocMin and call ProcessBound once more - if (NextIsForward) - { - while (E->Top.Y == E->Next->Bot.Y) E = E->Next; - //don't include top horizontals when parsing a bound a second time, - //they will be contained in the opposite bound ... - while (E != Result && IsHorizontal(*E)) E = E->Prev; - } - else - { - while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev; - while (E != Result && IsHorizontal(*E)) E = E->Next; - } - - if (E == Result) - { - if (NextIsForward) Result = E->Next; - else Result = E->Prev; - } - else - { - //there are more edges in the bound beyond result starting with E - if (NextIsForward) - E = Result->Next; - else - E = Result->Prev; - MinimaList::value_type locMin; - locMin.Y = E->Bot.Y; - locMin.LeftBound = 0; - locMin.RightBound = E; - E->WindDelta = 0; - Result = ProcessBound(E, NextIsForward); - m_MinimaList.push_back(locMin); - } - return Result; - } - - TEdge *EStart; - - if (IsHorizontal(*E)) - { - //We need to be careful with open paths because this may not be a - //true local minima (ie E may be following a skip edge). - //Also, consecutive horz. edges may start heading left before going right. - if (NextIsForward) - EStart = E->Prev; - else - EStart = E->Next; - if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge - { - if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X) - ReverseHorizontal(*E); - } - else if (EStart->Bot.X != E->Bot.X) - ReverseHorizontal(*E); - } - - EStart = E; - if (NextIsForward) - { - while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip) - Result = Result->Next; - if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) - { - //nb: at the top of a bound, horizontals are added to the bound - //only when the preceding edge attaches to the horizontal's left vertex - //unless a Skip edge is encountered when that becomes the top divide - Horz = Result; - while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; - if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev; - } - while (E != Result) - { - E->NextInLML = E->Next; - if (IsHorizontal(*E) && E != EStart && - E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); - E = E->Next; - } - if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) - ReverseHorizontal(*E); - Result = Result->Next; //move to the edge just beyond current bound - } else - { - while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip) - Result = Result->Prev; - if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) - { - Horz = Result; - while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; - if (Horz->Next->Top.X == Result->Prev->Top.X || - Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next; - } - - while (E != Result) - { - E->NextInLML = E->Prev; - if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) - ReverseHorizontal(*E); - E = E->Prev; - } - if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) - ReverseHorizontal(*E); - Result = Result->Prev; //move to the edge just beyond current bound - } - - return Result; -} -//------------------------------------------------------------------------------ - -bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) -{ -#ifdef use_lines - if (!Closed && PolyTyp == ptClip) - throw clipperException("AddPath: Open paths must be subject."); -#else - if (!Closed) - throw clipperException("AddPath: Open paths have been disabled."); -#endif - - int highI = (int)pg.size() -1; - if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; - while (highI > 0 && (pg[highI] == pg[highI -1])) --highI; - if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; - - //create a new edge array ... - TEdge *edges = new TEdge [highI +1]; - - bool IsFlat = true; - //1. Basic (first) edge initialization ... - try - { - edges[1].Curr = pg[1]; - RangeTest(pg[0], m_UseFullRange); - RangeTest(pg[highI], m_UseFullRange); - InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); - InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); - for (int i = highI - 1; i >= 1; --i) - { - RangeTest(pg[i], m_UseFullRange); - InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); - } - } - catch(...) - { - delete [] edges; - throw; //range test fails - } - TEdge *eStart = &edges[0]; - - //2. Remove duplicate vertices, and (when closed) collinear edges ... - TEdge *E = eStart, *eLoopStop = eStart; - for (;;) - { - //nb: allows matching start and end points when not Closed ... - if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart)) - { - if (E == E->Next) break; - if (E == eStart) eStart = E->Next; - E = RemoveEdge(E); - eLoopStop = E; - continue; - } - if (E->Prev == E->Next) - break; //only two vertices - else if (Closed && - SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && - (!m_PreserveCollinear || - !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) - { - //Collinear edges are allowed for open paths but in closed paths - //the default is to merge adjacent collinear edges into a single edge. - //However, if the PreserveCollinear property is enabled, only overlapping - //collinear edges (ie spikes) will be removed from closed paths. - if (E == eStart) eStart = E->Next; - E = RemoveEdge(E); - E = E->Prev; - eLoopStop = E; - continue; - } - E = E->Next; - if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break; - } - - if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) - { - delete [] edges; - return false; - } - - if (!Closed) - { - m_HasOpenPaths = true; - eStart->Prev->OutIdx = Skip; - } - - //3. Do second stage of edge initialization ... - E = eStart; - do - { - InitEdge2(*E, PolyTyp); - E = E->Next; - if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false; - } - while (E != eStart); - - //4. Finally, add edge bounds to LocalMinima list ... - - //Totally flat paths must be handled differently when adding them - //to LocalMinima list to avoid endless loops etc ... - if (IsFlat) - { - if (Closed) - { - delete [] edges; - return false; - } - E->Prev->OutIdx = Skip; - MinimaList::value_type locMin; - locMin.Y = E->Bot.Y; - locMin.LeftBound = 0; - locMin.RightBound = E; - locMin.RightBound->Side = esRight; - locMin.RightBound->WindDelta = 0; - for (;;) - { - if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); - if (E->Next->OutIdx == Skip) break; - E->NextInLML = E->Next; - E = E->Next; - } - m_MinimaList.push_back(locMin); - m_edges.push_back(edges); - return true; - } - - m_edges.push_back(edges); - bool leftBoundIsForward; - TEdge* EMin = 0; - - //workaround to avoid an endless loop in the while loop below when - //open paths have matching start and end points ... - if (E->Prev->Bot == E->Prev->Top) E = E->Next; - - for (;;) - { - E = FindNextLocMin(E); - if (E == EMin) break; - else if (!EMin) EMin = E; - - //E and E.Prev now share a local minima (left aligned if horizontal). - //Compare their slopes to find which starts which bound ... - MinimaList::value_type locMin; - locMin.Y = E->Bot.Y; - if (E->Dx < E->Prev->Dx) - { - locMin.LeftBound = E->Prev; - locMin.RightBound = E; - leftBoundIsForward = false; //Q.nextInLML = Q.prev - } else - { - locMin.LeftBound = E; - locMin.RightBound = E->Prev; - leftBoundIsForward = true; //Q.nextInLML = Q.next - } - - if (!Closed) locMin.LeftBound->WindDelta = 0; - else if (locMin.LeftBound->Next == locMin.RightBound) - locMin.LeftBound->WindDelta = -1; - else locMin.LeftBound->WindDelta = 1; - locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta; - - E = ProcessBound(locMin.LeftBound, leftBoundIsForward); - if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); - - TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward); - if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward); - - if (locMin.LeftBound->OutIdx == Skip) - locMin.LeftBound = 0; - else if (locMin.RightBound->OutIdx == Skip) - locMin.RightBound = 0; - m_MinimaList.push_back(locMin); - if (!leftBoundIsForward) E = E2; - } - return true; -} -//------------------------------------------------------------------------------ - -bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) -{ - bool result = false; - for (Paths::size_type i = 0; i < ppg.size(); ++i) - if (AddPath(ppg[i], PolyTyp, Closed)) result = true; - return result; -} -//------------------------------------------------------------------------------ - -void ClipperBase::Clear() -{ - DisposeLocalMinimaList(); - for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) - { - TEdge* edges = m_edges[i]; - delete [] edges; - } - m_edges.clear(); - m_UseFullRange = false; - m_HasOpenPaths = false; -} -//------------------------------------------------------------------------------ - -void ClipperBase::Reset() -{ - m_CurrentLM = m_MinimaList.begin(); - if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process - std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter()); - - m_Scanbeam = ScanbeamList(); //clears/resets priority_queue - //reset all edges ... - for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm) - { - InsertScanbeam(lm->Y); - TEdge* e = lm->LeftBound; - if (e) - { - e->Curr = e->Bot; - e->Side = esLeft; - e->OutIdx = Unassigned; - } - - e = lm->RightBound; - if (e) - { - e->Curr = e->Bot; - e->Side = esRight; - e->OutIdx = Unassigned; - } - } - m_ActiveEdges = 0; - m_CurrentLM = m_MinimaList.begin(); -} -//------------------------------------------------------------------------------ - -void ClipperBase::DisposeLocalMinimaList() -{ - m_MinimaList.clear(); - m_CurrentLM = m_MinimaList.begin(); -} -//------------------------------------------------------------------------------ - -bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin) -{ - if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false; - locMin = &(*m_CurrentLM); - ++m_CurrentLM; - return true; -} -//------------------------------------------------------------------------------ - -IntRect ClipperBase::GetBounds() -{ - IntRect result; - MinimaList::iterator lm = m_MinimaList.begin(); - if (lm == m_MinimaList.end()) - { - result.left = result.top = result.right = result.bottom = 0; - return result; - } - result.left = lm->LeftBound->Bot.X; - result.top = lm->LeftBound->Bot.Y; - result.right = lm->LeftBound->Bot.X; - result.bottom = lm->LeftBound->Bot.Y; - while (lm != m_MinimaList.end()) - { - //todo - needs fixing for open paths - result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y); - TEdge* e = lm->LeftBound; - for (;;) { - TEdge* bottomE = e; - while (e->NextInLML) - { - if (e->Bot.X < result.left) result.left = e->Bot.X; - if (e->Bot.X > result.right) result.right = e->Bot.X; - e = e->NextInLML; - } - result.left = std::min(result.left, e->Bot.X); - result.right = std::max(result.right, e->Bot.X); - result.left = std::min(result.left, e->Top.X); - result.right = std::max(result.right, e->Top.X); - result.top = std::min(result.top, e->Top.Y); - if (bottomE == lm->LeftBound) e = lm->RightBound; - else break; - } - ++lm; - } - return result; -} -//------------------------------------------------------------------------------ - -void ClipperBase::InsertScanbeam(const cInt Y) -{ - m_Scanbeam.push(Y); -} -//------------------------------------------------------------------------------ - -bool ClipperBase::PopScanbeam(cInt &Y) -{ - if (m_Scanbeam.empty()) return false; - Y = m_Scanbeam.top(); - m_Scanbeam.pop(); - while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates. - return true; -} -//------------------------------------------------------------------------------ - -void ClipperBase::DisposeAllOutRecs(){ - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - DisposeOutRec(i); - m_PolyOuts.clear(); -} -//------------------------------------------------------------------------------ - -void ClipperBase::DisposeOutRec(PolyOutList::size_type index) -{ - OutRec *outRec = m_PolyOuts[index]; - if (outRec->Pts) DisposeOutPts(outRec->Pts); - delete outRec; - m_PolyOuts[index] = 0; -} -//------------------------------------------------------------------------------ - -void ClipperBase::DeleteFromAEL(TEdge *e) -{ - TEdge* AelPrev = e->PrevInAEL; - TEdge* AelNext = e->NextInAEL; - if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted - if (AelPrev) AelPrev->NextInAEL = AelNext; - else m_ActiveEdges = AelNext; - if (AelNext) AelNext->PrevInAEL = AelPrev; - e->NextInAEL = 0; - e->PrevInAEL = 0; -} -//------------------------------------------------------------------------------ - -OutRec* ClipperBase::CreateOutRec() -{ - OutRec* result = new OutRec; - result->IsHole = false; - result->IsOpen = false; - result->FirstLeft = 0; - result->Pts = 0; - result->BottomPt = 0; - result->PolyNd = 0; - m_PolyOuts.push_back(result); - result->Idx = (int)m_PolyOuts.size() - 1; - return result; -} -//------------------------------------------------------------------------------ - -void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) -{ - //check that one or other edge hasn't already been removed from AEL ... - if (Edge1->NextInAEL == Edge1->PrevInAEL || - Edge2->NextInAEL == Edge2->PrevInAEL) return; - - if (Edge1->NextInAEL == Edge2) - { - TEdge* Next = Edge2->NextInAEL; - if (Next) Next->PrevInAEL = Edge1; - TEdge* Prev = Edge1->PrevInAEL; - if (Prev) Prev->NextInAEL = Edge2; - Edge2->PrevInAEL = Prev; - Edge2->NextInAEL = Edge1; - Edge1->PrevInAEL = Edge2; - Edge1->NextInAEL = Next; - } - else if (Edge2->NextInAEL == Edge1) - { - TEdge* Next = Edge1->NextInAEL; - if (Next) Next->PrevInAEL = Edge2; - TEdge* Prev = Edge2->PrevInAEL; - if (Prev) Prev->NextInAEL = Edge1; - Edge1->PrevInAEL = Prev; - Edge1->NextInAEL = Edge2; - Edge2->PrevInAEL = Edge1; - Edge2->NextInAEL = Next; - } - else - { - TEdge* Next = Edge1->NextInAEL; - TEdge* Prev = Edge1->PrevInAEL; - Edge1->NextInAEL = Edge2->NextInAEL; - if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1; - Edge1->PrevInAEL = Edge2->PrevInAEL; - if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1; - Edge2->NextInAEL = Next; - if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2; - Edge2->PrevInAEL = Prev; - if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2; - } - - if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1; - else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2; -} -//------------------------------------------------------------------------------ - -void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) -{ - if (!e->NextInLML) - throw clipperException("UpdateEdgeIntoAEL: invalid call"); - - e->NextInLML->OutIdx = e->OutIdx; - TEdge* AelPrev = e->PrevInAEL; - TEdge* AelNext = e->NextInAEL; - if (AelPrev) AelPrev->NextInAEL = e->NextInLML; - else m_ActiveEdges = e->NextInLML; - if (AelNext) AelNext->PrevInAEL = e->NextInLML; - e->NextInLML->Side = e->Side; - e->NextInLML->WindDelta = e->WindDelta; - e->NextInLML->WindCnt = e->WindCnt; - e->NextInLML->WindCnt2 = e->WindCnt2; - e = e->NextInLML; - e->Curr = e->Bot; - e->PrevInAEL = AelPrev; - e->NextInAEL = AelNext; - if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y); -} -//------------------------------------------------------------------------------ - -bool ClipperBase::LocalMinimaPending() -{ - return (m_CurrentLM != m_MinimaList.end()); -} - -//------------------------------------------------------------------------------ -// TClipper methods ... -//------------------------------------------------------------------------------ - -Clipper::Clipper(int initOptions) : ClipperBase() //constructor -{ - m_ExecuteLocked = false; - m_UseFullRange = false; - m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); - m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); - m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); - m_HasOpenPaths = false; -#ifdef use_xyz - m_ZFill = 0; -#endif -} -//------------------------------------------------------------------------------ - -#ifdef use_xyz -void Clipper::ZFillFunction(ZFillCallback zFillFunc) -{ - m_ZFill = zFillFunc; -} -//------------------------------------------------------------------------------ -#endif - -bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType) -{ - return Execute(clipType, solution, fillType, fillType); -} -//------------------------------------------------------------------------------ - -bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType) -{ - return Execute(clipType, polytree, fillType, fillType); -} -//------------------------------------------------------------------------------ - -bool Clipper::Execute(ClipType clipType, Paths &solution, - PolyFillType subjFillType, PolyFillType clipFillType) -{ - if( m_ExecuteLocked ) return false; - if (m_HasOpenPaths) - throw clipperException("Error: PolyTree struct is needed for open path clipping."); - m_ExecuteLocked = true; - solution.resize(0); - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = false; - bool succeeded = ExecuteInternal(); - if (succeeded) BuildResult(solution); - DisposeAllOutRecs(); - m_ExecuteLocked = false; - return succeeded; -} -//------------------------------------------------------------------------------ - -bool Clipper::Execute(ClipType clipType, PolyTree& polytree, - PolyFillType subjFillType, PolyFillType clipFillType) -{ - if( m_ExecuteLocked ) return false; - m_ExecuteLocked = true; - m_SubjFillType = subjFillType; - m_ClipFillType = clipFillType; - m_ClipType = clipType; - m_UsingPolyTree = true; - bool succeeded = ExecuteInternal(); - if (succeeded) BuildResult2(polytree); - DisposeAllOutRecs(); - m_ExecuteLocked = false; - return succeeded; -} -//------------------------------------------------------------------------------ - -void Clipper::FixHoleLinkage(OutRec &outrec) -{ - //skip OutRecs that (a) contain outermost polygons or - //(b) already have the correct owner/child linkage ... - if (!outrec.FirstLeft || - (outrec.IsHole != outrec.FirstLeft->IsHole && - outrec.FirstLeft->Pts)) return; - - OutRec* orfl = outrec.FirstLeft; - while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts)) - orfl = orfl->FirstLeft; - outrec.FirstLeft = orfl; -} -//------------------------------------------------------------------------------ - -bool Clipper::ExecuteInternal() -{ - bool succeeded = true; - try { - Reset(); - m_Maxima = MaximaList(); - m_SortedEdges = 0; - - succeeded = true; - cInt botY, topY; - if (!PopScanbeam(botY)) return false; - InsertLocalMinimaIntoAEL(botY); - while (PopScanbeam(topY) || LocalMinimaPending()) - { - ProcessHorizontals(); - ClearGhostJoins(); - if (!ProcessIntersections(topY)) - { - succeeded = false; - break; - } - ProcessEdgesAtTopOfScanbeam(topY); - botY = topY; - InsertLocalMinimaIntoAEL(botY); - } - } - catch(...) - { - succeeded = false; - } - - if (succeeded) - { - //fix orientations ... - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - OutRec *outRec = m_PolyOuts[i]; - if (!outRec->Pts || outRec->IsOpen) continue; - if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0)) - ReversePolyPtLinks(outRec->Pts); - } - - if (!m_Joins.empty()) JoinCommonEdges(); - - //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - OutRec *outRec = m_PolyOuts[i]; - if (!outRec->Pts) continue; - if (outRec->IsOpen) - FixupOutPolyline(*outRec); - else - FixupOutPolygon(*outRec); - } - - if (m_StrictSimple) DoSimplePolygons(); - } - - ClearJoins(); - ClearGhostJoins(); - return succeeded; -} -//------------------------------------------------------------------------------ - -void Clipper::SetWindingCount(TEdge &edge) -{ - TEdge *e = edge.PrevInAEL; - //find the edge of the same polytype that immediately preceeds 'edge' in AEL - while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; - if (!e) - { - if (edge.WindDelta == 0) - { - PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType); - edge.WindCnt = (pft == pftNegative ? -1 : 1); - } - else - edge.WindCnt = edge.WindDelta; - edge.WindCnt2 = 0; - e = m_ActiveEdges; //ie get ready to calc WindCnt2 - } - else if (edge.WindDelta == 0 && m_ClipType != ctUnion) - { - edge.WindCnt = 1; - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - else if (IsEvenOddFillType(edge)) - { - //EvenOdd filling ... - if (edge.WindDelta == 0) - { - //are we inside a subj polygon ... - bool Inside = true; - TEdge *e2 = e->PrevInAEL; - while (e2) - { - if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) - Inside = !Inside; - e2 = e2->PrevInAEL; - } - edge.WindCnt = (Inside ? 0 : 1); - } - else - { - edge.WindCnt = edge.WindDelta; - } - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - else - { - //nonZero, Positive or Negative filling ... - if (e->WindCnt * e->WindDelta < 0) - { - //prev edge is 'decreasing' WindCount (WC) toward zero - //so we're outside the previous polygon ... - if (Abs(e->WindCnt) > 1) - { - //outside prev poly but still inside another. - //when reversing direction of prev poly use the same WC - if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; - //otherwise continue to 'decrease' WC ... - else edge.WindCnt = e->WindCnt + edge.WindDelta; - } - else - //now outside all polys of same polytype so set own WC ... - edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); - } else - { - //prev edge is 'increasing' WindCount (WC) away from zero - //so we're inside the previous polygon ... - if (edge.WindDelta == 0) - edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); - //if wind direction is reversing prev then use same WC - else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; - //otherwise add to WC ... - else edge.WindCnt = e->WindCnt + edge.WindDelta; - } - edge.WindCnt2 = e->WindCnt2; - e = e->NextInAEL; //ie get ready to calc WindCnt2 - } - - //update WindCnt2 ... - if (IsEvenOddAltFillType(edge)) - { - //EvenOdd filling ... - while (e != &edge) - { - if (e->WindDelta != 0) - edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); - e = e->NextInAEL; - } - } else - { - //nonZero, Positive or Negative filling ... - while ( e != &edge ) - { - edge.WindCnt2 += e->WindDelta; - e = e->NextInAEL; - } - } -} -//------------------------------------------------------------------------------ - -bool Clipper::IsEvenOddFillType(const TEdge& edge) const -{ - if (edge.PolyTyp == ptSubject) - return m_SubjFillType == pftEvenOdd; else - return m_ClipFillType == pftEvenOdd; -} -//------------------------------------------------------------------------------ - -bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const -{ - if (edge.PolyTyp == ptSubject) - return m_ClipFillType == pftEvenOdd; else - return m_SubjFillType == pftEvenOdd; -} -//------------------------------------------------------------------------------ - -bool Clipper::IsContributing(const TEdge& edge) const -{ - PolyFillType pft, pft2; - if (edge.PolyTyp == ptSubject) - { - pft = m_SubjFillType; - pft2 = m_ClipFillType; - } else - { - pft = m_ClipFillType; - pft2 = m_SubjFillType; - } - - switch(pft) - { - case pftEvenOdd: - //return false if a subj line has been flagged as inside a subj polygon - if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; - break; - case pftNonZero: - if (Abs(edge.WindCnt) != 1) return false; - break; - case pftPositive: - if (edge.WindCnt != 1) return false; - break; - default: //pftNegative - if (edge.WindCnt != -1) return false; - } - - switch(m_ClipType) - { - case ctIntersection: - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 != 0); - case pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - break; - case ctUnion: - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - break; - case ctDifference: - if (edge.PolyTyp == ptSubject) - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 != 0); - case pftPositive: - return (edge.WindCnt2 > 0); - default: - return (edge.WindCnt2 < 0); - } - break; - case ctXor: - if (edge.WindDelta == 0) //XOr always contributing unless open - switch(pft2) - { - case pftEvenOdd: - case pftNonZero: - return (edge.WindCnt2 == 0); - case pftPositive: - return (edge.WindCnt2 <= 0); - default: - return (edge.WindCnt2 >= 0); - } - else - return true; - break; - default: - return true; - } -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) -{ - OutPt* result; - TEdge *e, *prevE; - if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) - { - result = AddOutPt(e1, Pt); - e2->OutIdx = e1->OutIdx; - e1->Side = esLeft; - e2->Side = esRight; - e = e1; - if (e->PrevInAEL == e2) - prevE = e2->PrevInAEL; - else - prevE = e->PrevInAEL; - } else - { - result = AddOutPt(e2, Pt); - e1->OutIdx = e2->OutIdx; - e1->Side = esRight; - e2->Side = esLeft; - e = e2; - if (e->PrevInAEL == e1) - prevE = e1->PrevInAEL; - else - prevE = e->PrevInAEL; - } - - if (prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y) - { - cInt xPrev = TopX(*prevE, Pt.Y); - cInt xE = TopX(*e, Pt.Y); - if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) && - SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange)) - { - OutPt* outPt = AddOutPt(prevE, Pt); - AddJoin(result, outPt, e->Top); - } - } - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) -{ - AddOutPt( e1, Pt ); - if (e2->WindDelta == 0) AddOutPt(e2, Pt); - if( e1->OutIdx == e2->OutIdx ) - { - e1->OutIdx = Unassigned; - e2->OutIdx = Unassigned; - } - else if (e1->OutIdx < e2->OutIdx) - AppendPolygon(e1, e2); - else - AppendPolygon(e2, e1); -} -//------------------------------------------------------------------------------ - -void Clipper::AddEdgeToSEL(TEdge *edge) -{ - //SEL pointers in PEdge are reused to build a list of horizontal edges. - //However, we don't need to worry about order with horizontal edge processing. - if( !m_SortedEdges ) - { - m_SortedEdges = edge; - edge->PrevInSEL = 0; - edge->NextInSEL = 0; - } - else - { - edge->NextInSEL = m_SortedEdges; - edge->PrevInSEL = 0; - m_SortedEdges->PrevInSEL = edge; - m_SortedEdges = edge; - } -} -//------------------------------------------------------------------------------ - -bool Clipper::PopEdgeFromSEL(TEdge *&edge) -{ - if (!m_SortedEdges) return false; - edge = m_SortedEdges; - DeleteFromSEL(m_SortedEdges); - return true; -} -//------------------------------------------------------------------------------ - -void Clipper::CopyAELToSEL() -{ - TEdge* e = m_ActiveEdges; - m_SortedEdges = e; - while ( e ) - { - e->PrevInSEL = e->PrevInAEL; - e->NextInSEL = e->NextInAEL; - e = e->NextInAEL; - } -} -//------------------------------------------------------------------------------ - -void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) -{ - Join* j = new Join; - j->OutPt1 = op1; - j->OutPt2 = op2; - j->OffPt = OffPt; - m_Joins.push_back(j); -} -//------------------------------------------------------------------------------ - -void Clipper::ClearJoins() -{ - for (JoinList::size_type i = 0; i < m_Joins.size(); i++) - delete m_Joins[i]; - m_Joins.resize(0); -} -//------------------------------------------------------------------------------ - -void Clipper::ClearGhostJoins() -{ - for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++) - delete m_GhostJoins[i]; - m_GhostJoins.resize(0); -} -//------------------------------------------------------------------------------ - -void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) -{ - Join* j = new Join; - j->OutPt1 = op; - j->OutPt2 = 0; - j->OffPt = OffPt; - m_GhostJoins.push_back(j); -} -//------------------------------------------------------------------------------ - -void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) -{ - const LocalMinimum *lm; - while (PopLocalMinima(botY, lm)) - { - TEdge* lb = lm->LeftBound; - TEdge* rb = lm->RightBound; - - OutPt *Op1 = 0; - if (!lb) - { - //nb: don't insert LB into either AEL or SEL - InsertEdgeIntoAEL(rb, 0); - SetWindingCount(*rb); - if (IsContributing(*rb)) - Op1 = AddOutPt(rb, rb->Bot); - } - else if (!rb) - { - InsertEdgeIntoAEL(lb, 0); - SetWindingCount(*lb); - if (IsContributing(*lb)) - Op1 = AddOutPt(lb, lb->Bot); - InsertScanbeam(lb->Top.Y); - } - else - { - InsertEdgeIntoAEL(lb, 0); - InsertEdgeIntoAEL(rb, lb); - SetWindingCount( *lb ); - rb->WindCnt = lb->WindCnt; - rb->WindCnt2 = lb->WindCnt2; - if (IsContributing(*lb)) - Op1 = AddLocalMinPoly(lb, rb, lb->Bot); - InsertScanbeam(lb->Top.Y); - } - - if (rb) - { - if (IsHorizontal(*rb)) - { - AddEdgeToSEL(rb); - if (rb->NextInLML) - InsertScanbeam(rb->NextInLML->Top.Y); - } - else InsertScanbeam( rb->Top.Y ); - } - - if (!lb || !rb) continue; - - //if any output polygons share an edge, they'll need joining later ... - if (Op1 && IsHorizontal(*rb) && - m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) - { - for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) - { - Join* jr = m_GhostJoins[i]; - //if the horizontal Rb and a 'ghost' horizontal overlap, then convert - //the 'ghost' join to a real join ready for later ... - if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X)) - AddJoin(jr->OutPt1, Op1, jr->OffPt); - } - } - - if (lb->OutIdx >= 0 && lb->PrevInAEL && - lb->PrevInAEL->Curr.X == lb->Bot.X && - lb->PrevInAEL->OutIdx >= 0 && - SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) && - (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) - { - OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); - AddJoin(Op1, Op2, lb->Top); - } - - if(lb->NextInAEL != rb) - { - - if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && - SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) && - (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) - { - OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); - AddJoin(Op1, Op2, rb->Top); - } - - TEdge* e = lb->NextInAEL; - if (e) - { - while( e != rb ) - { - //nb: For calculating winding counts etc, IntersectEdges() assumes - //that param1 will be to the Right of param2 ABOVE the intersection ... - IntersectEdges(rb , e , lb->Curr); //order important here - e = e->NextInAEL; - } - } - } - - } -} -//------------------------------------------------------------------------------ - -void Clipper::DeleteFromSEL(TEdge *e) -{ - TEdge* SelPrev = e->PrevInSEL; - TEdge* SelNext = e->NextInSEL; - if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted - if( SelPrev ) SelPrev->NextInSEL = SelNext; - else m_SortedEdges = SelNext; - if( SelNext ) SelNext->PrevInSEL = SelPrev; - e->NextInSEL = 0; - e->PrevInSEL = 0; -} -//------------------------------------------------------------------------------ - -#ifdef use_xyz -void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2) -{ - if (pt.Z != 0 || !m_ZFill) return; - else if (pt == e1.Bot) pt.Z = e1.Bot.Z; - else if (pt == e1.Top) pt.Z = e1.Top.Z; - else if (pt == e2.Bot) pt.Z = e2.Bot.Z; - else if (pt == e2.Top) pt.Z = e2.Top.Z; - else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt); -} -//------------------------------------------------------------------------------ -#endif - -void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt) -{ - bool e1Contributing = ( e1->OutIdx >= 0 ); - bool e2Contributing = ( e2->OutIdx >= 0 ); - -#ifdef use_xyz - SetZ(Pt, *e1, *e2); -#endif - -#ifdef use_lines - //if either edge is on an OPEN path ... - if (e1->WindDelta == 0 || e2->WindDelta == 0) - { - //ignore subject-subject open path intersections UNLESS they - //are both open paths, AND they are both 'contributing maximas' ... - if (e1->WindDelta == 0 && e2->WindDelta == 0) return; - - //if intersecting a subj line with a subj poly ... - else if (e1->PolyTyp == e2->PolyTyp && - e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) - { - if (e1->WindDelta == 0) - { - if (e2Contributing) - { - AddOutPt(e1, Pt); - if (e1Contributing) e1->OutIdx = Unassigned; - } - } - else - { - if (e1Contributing) - { - AddOutPt(e2, Pt); - if (e2Contributing) e2->OutIdx = Unassigned; - } - } - } - else if (e1->PolyTyp != e2->PolyTyp) - { - //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... - if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && - (m_ClipType != ctUnion || e2->WindCnt2 == 0)) - { - AddOutPt(e1, Pt); - if (e1Contributing) e1->OutIdx = Unassigned; - } - else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && - (m_ClipType != ctUnion || e1->WindCnt2 == 0)) - { - AddOutPt(e2, Pt); - if (e2Contributing) e2->OutIdx = Unassigned; - } - } - return; - } -#endif - - //update winding counts... - //assumes that e1 will be to the Right of e2 ABOVE the intersection - if ( e1->PolyTyp == e2->PolyTyp ) - { - if ( IsEvenOddFillType( *e1) ) - { - int oldE1WindCnt = e1->WindCnt; - e1->WindCnt = e2->WindCnt; - e2->WindCnt = oldE1WindCnt; - } else - { - if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; - else e1->WindCnt += e2->WindDelta; - if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; - else e2->WindCnt -= e1->WindDelta; - } - } else - { - if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; - else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; - if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; - else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; - } - - PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; - if (e1->PolyTyp == ptSubject) - { - e1FillType = m_SubjFillType; - e1FillType2 = m_ClipFillType; - } else - { - e1FillType = m_ClipFillType; - e1FillType2 = m_SubjFillType; - } - if (e2->PolyTyp == ptSubject) - { - e2FillType = m_SubjFillType; - e2FillType2 = m_ClipFillType; - } else - { - e2FillType = m_ClipFillType; - e2FillType2 = m_SubjFillType; - } - - cInt e1Wc, e2Wc; - switch (e1FillType) - { - case pftPositive: e1Wc = e1->WindCnt; break; - case pftNegative: e1Wc = -e1->WindCnt; break; - default: e1Wc = Abs(e1->WindCnt); - } - switch(e2FillType) - { - case pftPositive: e2Wc = e2->WindCnt; break; - case pftNegative: e2Wc = -e2->WindCnt; break; - default: e2Wc = Abs(e2->WindCnt); - } - - if ( e1Contributing && e2Contributing ) - { - if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || - (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) - { - AddLocalMaxPoly(e1, e2, Pt); - } - else - { - AddOutPt(e1, Pt); - AddOutPt(e2, Pt); - SwapSides( *e1 , *e2 ); - SwapPolyIndexes( *e1 , *e2 ); - } - } - else if ( e1Contributing ) - { - if (e2Wc == 0 || e2Wc == 1) - { - AddOutPt(e1, Pt); - SwapSides(*e1, *e2); - SwapPolyIndexes(*e1, *e2); - } - } - else if ( e2Contributing ) - { - if (e1Wc == 0 || e1Wc == 1) - { - AddOutPt(e2, Pt); - SwapSides(*e1, *e2); - SwapPolyIndexes(*e1, *e2); - } - } - else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) - { - //neither edge is currently contributing ... - - cInt e1Wc2, e2Wc2; - switch (e1FillType2) - { - case pftPositive: e1Wc2 = e1->WindCnt2; break; - case pftNegative : e1Wc2 = -e1->WindCnt2; break; - default: e1Wc2 = Abs(e1->WindCnt2); - } - switch (e2FillType2) - { - case pftPositive: e2Wc2 = e2->WindCnt2; break; - case pftNegative: e2Wc2 = -e2->WindCnt2; break; - default: e2Wc2 = Abs(e2->WindCnt2); - } - - if (e1->PolyTyp != e2->PolyTyp) - { - AddLocalMinPoly(e1, e2, Pt); - } - else if (e1Wc == 1 && e2Wc == 1) - switch( m_ClipType ) { - case ctIntersection: - if (e1Wc2 > 0 && e2Wc2 > 0) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctUnion: - if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctDifference: - if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || - ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) - AddLocalMinPoly(e1, e2, Pt); - break; - case ctXor: - AddLocalMinPoly(e1, e2, Pt); - } - else - SwapSides( *e1, *e2 ); - } -} -//------------------------------------------------------------------------------ - -void Clipper::SetHoleState(TEdge *e, OutRec *outrec) -{ - TEdge *e2 = e->PrevInAEL; - TEdge *eTmp = 0; - while (e2) - { - if (e2->OutIdx >= 0 && e2->WindDelta != 0) - { - if (!eTmp) eTmp = e2; - else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0; - } - e2 = e2->PrevInAEL; - } - if (!eTmp) - { - outrec->FirstLeft = 0; - outrec->IsHole = false; - } - else - { - outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx]; - outrec->IsHole = !outrec->FirstLeft->IsHole; - } -} -//------------------------------------------------------------------------------ - -OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) -{ - //work out which polygon fragment has the correct hole state ... - if (!outRec1->BottomPt) - outRec1->BottomPt = GetBottomPt(outRec1->Pts); - if (!outRec2->BottomPt) - outRec2->BottomPt = GetBottomPt(outRec2->Pts); - OutPt *OutPt1 = outRec1->BottomPt; - OutPt *OutPt2 = outRec2->BottomPt; - if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1; - else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2; - else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1; - else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2; - else if (OutPt1->Next == OutPt1) return outRec2; - else if (OutPt2->Next == OutPt2) return outRec1; - else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; - else return outRec2; -} -//------------------------------------------------------------------------------ - -bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2) -{ - do - { - outRec1 = outRec1->FirstLeft; - if (outRec1 == outRec2) return true; - } while (outRec1); - return false; -} -//------------------------------------------------------------------------------ - -OutRec* Clipper::GetOutRec(int Idx) -{ - OutRec* outrec = m_PolyOuts[Idx]; - while (outrec != m_PolyOuts[outrec->Idx]) - outrec = m_PolyOuts[outrec->Idx]; - return outrec; -} -//------------------------------------------------------------------------------ - -void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) -{ - //get the start and ends of both output polygons ... - OutRec *outRec1 = m_PolyOuts[e1->OutIdx]; - OutRec *outRec2 = m_PolyOuts[e2->OutIdx]; - - OutRec *holeStateRec; - if (OutRec1RightOfOutRec2(outRec1, outRec2)) - holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) - holeStateRec = outRec1; - else - holeStateRec = GetLowermostRec(outRec1, outRec2); - - //get the start and ends of both output polygons and - //join e2 poly onto e1 poly and delete pointers to e2 ... - - OutPt* p1_lft = outRec1->Pts; - OutPt* p1_rt = p1_lft->Prev; - OutPt* p2_lft = outRec2->Pts; - OutPt* p2_rt = p2_lft->Prev; - - //join e2 poly onto e1 poly and delete pointers to e2 ... - if( e1->Side == esLeft ) - { - if( e2->Side == esLeft ) - { - //z y x a b c - ReversePolyPtLinks(p2_lft); - p2_lft->Next = p1_lft; - p1_lft->Prev = p2_lft; - p1_rt->Next = p2_rt; - p2_rt->Prev = p1_rt; - outRec1->Pts = p2_rt; - } else - { - //x y z a b c - p2_rt->Next = p1_lft; - p1_lft->Prev = p2_rt; - p2_lft->Prev = p1_rt; - p1_rt->Next = p2_lft; - outRec1->Pts = p2_lft; - } - } else - { - if( e2->Side == esRight ) - { - //a b c z y x - ReversePolyPtLinks(p2_lft); - p1_rt->Next = p2_rt; - p2_rt->Prev = p1_rt; - p2_lft->Next = p1_lft; - p1_lft->Prev = p2_lft; - } else - { - //a b c x y z - p1_rt->Next = p2_lft; - p2_lft->Prev = p1_rt; - p1_lft->Prev = p2_rt; - p2_rt->Next = p1_lft; - } - } - - outRec1->BottomPt = 0; - if (holeStateRec == outRec2) - { - if (outRec2->FirstLeft != outRec1) - outRec1->FirstLeft = outRec2->FirstLeft; - outRec1->IsHole = outRec2->IsHole; - } - outRec2->Pts = 0; - outRec2->BottomPt = 0; - outRec2->FirstLeft = outRec1; - - int OKIdx = e1->OutIdx; - int ObsoleteIdx = e2->OutIdx; - - e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly - e2->OutIdx = Unassigned; - - TEdge* e = m_ActiveEdges; - while( e ) - { - if( e->OutIdx == ObsoleteIdx ) - { - e->OutIdx = OKIdx; - e->Side = e1->Side; - break; - } - e = e->NextInAEL; - } - - outRec2->Idx = outRec1->Idx; -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) -{ - if( e->OutIdx < 0 ) - { - OutRec *outRec = CreateOutRec(); - outRec->IsOpen = (e->WindDelta == 0); - OutPt* newOp = new OutPt; - outRec->Pts = newOp; - newOp->Idx = outRec->Idx; - newOp->Pt = pt; - newOp->Next = newOp; - newOp->Prev = newOp; - if (!outRec->IsOpen) - SetHoleState(e, outRec); - e->OutIdx = outRec->Idx; - return newOp; - } else - { - OutRec *outRec = m_PolyOuts[e->OutIdx]; - //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' - OutPt* op = outRec->Pts; - - bool ToFront = (e->Side == esLeft); - if (ToFront && (pt == op->Pt)) return op; - else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; - - OutPt* newOp = new OutPt; - newOp->Idx = outRec->Idx; - newOp->Pt = pt; - newOp->Next = op; - newOp->Prev = op->Prev; - newOp->Prev->Next = newOp; - op->Prev = newOp; - if (ToFront) outRec->Pts = newOp; - return newOp; - } -} -//------------------------------------------------------------------------------ - -OutPt* Clipper::GetLastOutPt(TEdge *e) -{ - OutRec *outRec = m_PolyOuts[e->OutIdx]; - if (e->Side == esLeft) - return outRec->Pts; - else - return outRec->Pts->Prev; -} -//------------------------------------------------------------------------------ - -void Clipper::ProcessHorizontals() -{ - TEdge* horzEdge; - while (PopEdgeFromSEL(horzEdge)) - ProcessHorizontal(horzEdge); -} -//------------------------------------------------------------------------------ - -inline bool IsMinima(TEdge *e) -{ - return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e); -} -//------------------------------------------------------------------------------ - -inline bool IsMaxima(TEdge *e, const cInt Y) -{ - return e && e->Top.Y == Y && !e->NextInLML; -} -//------------------------------------------------------------------------------ - -inline bool IsIntermediate(TEdge *e, const cInt Y) -{ - return e->Top.Y == Y && e->NextInLML; -} -//------------------------------------------------------------------------------ - -TEdge *GetMaximaPair(TEdge *e) -{ - if ((e->Next->Top == e->Top) && !e->Next->NextInLML) - return e->Next; - else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) - return e->Prev; - else return 0; -} -//------------------------------------------------------------------------------ - -TEdge *GetMaximaPairEx(TEdge *e) -{ - //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal) - TEdge* result = GetMaximaPair(e); - if (result && (result->OutIdx == Skip || - (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0; - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) -{ - if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; - if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; - - if( Edge1->NextInSEL == Edge2 ) - { - TEdge* Next = Edge2->NextInSEL; - if( Next ) Next->PrevInSEL = Edge1; - TEdge* Prev = Edge1->PrevInSEL; - if( Prev ) Prev->NextInSEL = Edge2; - Edge2->PrevInSEL = Prev; - Edge2->NextInSEL = Edge1; - Edge1->PrevInSEL = Edge2; - Edge1->NextInSEL = Next; - } - else if( Edge2->NextInSEL == Edge1 ) - { - TEdge* Next = Edge1->NextInSEL; - if( Next ) Next->PrevInSEL = Edge2; - TEdge* Prev = Edge2->PrevInSEL; - if( Prev ) Prev->NextInSEL = Edge1; - Edge1->PrevInSEL = Prev; - Edge1->NextInSEL = Edge2; - Edge2->PrevInSEL = Edge1; - Edge2->NextInSEL = Next; - } - else - { - TEdge* Next = Edge1->NextInSEL; - TEdge* Prev = Edge1->PrevInSEL; - Edge1->NextInSEL = Edge2->NextInSEL; - if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; - Edge1->PrevInSEL = Edge2->PrevInSEL; - if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; - Edge2->NextInSEL = Next; - if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; - Edge2->PrevInSEL = Prev; - if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; - } - - if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; - else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; -} -//------------------------------------------------------------------------------ - -TEdge* GetNextInAEL(TEdge *e, Direction dir) -{ - return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL; -} -//------------------------------------------------------------------------------ - -void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) -{ - if (HorzEdge.Bot.X < HorzEdge.Top.X) - { - Left = HorzEdge.Bot.X; - Right = HorzEdge.Top.X; - Dir = dLeftToRight; - } else - { - Left = HorzEdge.Top.X; - Right = HorzEdge.Bot.X; - Dir = dRightToLeft; - } -} -//------------------------------------------------------------------------ - -/******************************************************************************* -* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * -* Bottom of a scanbeam) are processed as if layered. The order in which HEs * -* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] * -* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * -* and with other non-horizontal edges [*]. Once these intersections are * -* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * -* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * -*******************************************************************************/ - -void Clipper::ProcessHorizontal(TEdge *horzEdge) -{ - Direction dir; - cInt horzLeft, horzRight; - bool IsOpen = (horzEdge->WindDelta == 0); - - GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); - - TEdge* eLastHorz = horzEdge, *eMaxPair = 0; - while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) - eLastHorz = eLastHorz->NextInLML; - if (!eLastHorz->NextInLML) - eMaxPair = GetMaximaPair(eLastHorz); - - MaximaList::const_iterator maxIt; - MaximaList::const_reverse_iterator maxRit; - if (m_Maxima.size() > 0) - { - //get the first maxima in range (X) ... - if (dir == dLeftToRight) - { - maxIt = m_Maxima.begin(); - while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++; - if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X) - maxIt = m_Maxima.end(); - } - else - { - maxRit = m_Maxima.rbegin(); - while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++; - if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X) - maxRit = m_Maxima.rend(); - } - } - - OutPt* op1 = 0; - - for (;;) //loop through consec. horizontal edges - { - - bool IsLastHorz = (horzEdge == eLastHorz); - TEdge* e = GetNextInAEL(horzEdge, dir); - while(e) - { - - //this code block inserts extra coords into horizontal edges (in output - //polygons) whereever maxima touch these horizontal edges. This helps - //'simplifying' polygons (ie if the Simplify property is set). - if (m_Maxima.size() > 0) - { - if (dir == dLeftToRight) - { - while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X) - { - if (horzEdge->OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y)); - maxIt++; - } - } - else - { - while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X) - { - if (horzEdge->OutIdx >= 0 && !IsOpen) - AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y)); - maxRit++; - } - } - }; - - if ((dir == dLeftToRight && e->Curr.X > horzRight) || - (dir == dRightToLeft && e->Curr.X < horzLeft)) break; - - //Also break if we've got to the end of an intermediate horizontal edge ... - //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. - if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML && - e->Dx < horzEdge->NextInLML->Dx) break; - - if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times - { -#ifdef use_xyz - if (dir == dLeftToRight) SetZ(e->Curr, *horzEdge, *e); - else SetZ(e->Curr, *e, *horzEdge); -#endif - op1 = AddOutPt(horzEdge, e->Curr); - TEdge* eNextHorz = m_SortedEdges; - while (eNextHorz) - { - if (eNextHorz->OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge->Bot.X, - horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) - { - OutPt* op2 = GetLastOutPt(eNextHorz); - AddJoin(op2, op1, eNextHorz->Top); - } - eNextHorz = eNextHorz->NextInSEL; - } - AddGhostJoin(op1, horzEdge->Bot); - } - - //OK, so far we're still in range of the horizontal Edge but make sure - //we're at the last of consec. horizontals when matching with eMaxPair - if(e == eMaxPair && IsLastHorz) - { - if (horzEdge->OutIdx >= 0) - AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top); - DeleteFromAEL(horzEdge); - DeleteFromAEL(eMaxPair); - return; - } - - if(dir == dLeftToRight) - { - IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); - IntersectEdges(horzEdge, e, Pt); - } - else - { - IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); - IntersectEdges( e, horzEdge, Pt); - } - TEdge* eNext = GetNextInAEL(e, dir); - SwapPositionsInAEL( horzEdge, e ); - e = eNext; - } //end while(e) - - //Break out of loop if HorzEdge.NextInLML is not also horizontal ... - if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break; - - UpdateEdgeIntoAEL(horzEdge); - if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); - GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); - - } //end for (;;) - - if (horzEdge->OutIdx >= 0 && !op1) - { - op1 = GetLastOutPt(horzEdge); - TEdge* eNextHorz = m_SortedEdges; - while (eNextHorz) - { - if (eNextHorz->OutIdx >= 0 && - HorzSegmentsOverlap(horzEdge->Bot.X, - horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) - { - OutPt* op2 = GetLastOutPt(eNextHorz); - AddJoin(op2, op1, eNextHorz->Top); - } - eNextHorz = eNextHorz->NextInSEL; - } - AddGhostJoin(op1, horzEdge->Top); - } - - if (horzEdge->NextInLML) - { - if(horzEdge->OutIdx >= 0) - { - op1 = AddOutPt( horzEdge, horzEdge->Top); - UpdateEdgeIntoAEL(horzEdge); - if (horzEdge->WindDelta == 0) return; - //nb: HorzEdge is no longer horizontal here - TEdge* ePrev = horzEdge->PrevInAEL; - TEdge* eNext = horzEdge->NextInAEL; - if (ePrev && ePrev->Curr.X == horzEdge->Bot.X && - ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 && - (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && - SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) - { - OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); - AddJoin(op1, op2, horzEdge->Top); - } - else if (eNext && eNext->Curr.X == horzEdge->Bot.X && - eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 && - eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && - SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) - { - OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); - AddJoin(op1, op2, horzEdge->Top); - } - } - else - UpdateEdgeIntoAEL(horzEdge); - } - else - { - if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); - DeleteFromAEL(horzEdge); - } -} -//------------------------------------------------------------------------------ - -bool Clipper::ProcessIntersections(const cInt topY) -{ - if( !m_ActiveEdges ) return true; - try { - BuildIntersectList(topY); - size_t IlSize = m_IntersectList.size(); - if (IlSize == 0) return true; - if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); - else return false; - } - catch(...) - { - m_SortedEdges = 0; - DisposeIntersectNodes(); - throw clipperException("ProcessIntersections error"); - } - m_SortedEdges = 0; - return true; -} -//------------------------------------------------------------------------------ - -void Clipper::DisposeIntersectNodes() -{ - for (size_t i = 0; i < m_IntersectList.size(); ++i ) - delete m_IntersectList[i]; - m_IntersectList.clear(); -} -//------------------------------------------------------------------------------ - -void Clipper::BuildIntersectList(const cInt topY) -{ - if ( !m_ActiveEdges ) return; - - //prepare for sorting ... - TEdge* e = m_ActiveEdges; - m_SortedEdges = e; - while( e ) - { - e->PrevInSEL = e->PrevInAEL; - e->NextInSEL = e->NextInAEL; - e->Curr.X = TopX( *e, topY ); - e = e->NextInAEL; - } - - //bubblesort ... - bool isModified; - do - { - isModified = false; - e = m_SortedEdges; - while( e->NextInSEL ) - { - TEdge *eNext = e->NextInSEL; - IntPoint Pt; - if(e->Curr.X > eNext->Curr.X) - { - IntersectPoint(*e, *eNext, Pt); - if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY); - IntersectNode * newNode = new IntersectNode; - newNode->Edge1 = e; - newNode->Edge2 = eNext; - newNode->Pt = Pt; - m_IntersectList.push_back(newNode); - - SwapPositionsInSEL(e, eNext); - isModified = true; - } - else - e = eNext; - } - if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; - else break; - } - while ( isModified ); - m_SortedEdges = 0; //important -} -//------------------------------------------------------------------------------ - - -void Clipper::ProcessIntersectList() -{ - for (size_t i = 0; i < m_IntersectList.size(); ++i) - { - IntersectNode* iNode = m_IntersectList[i]; - { - IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt); - SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 ); - } - delete iNode; - } - m_IntersectList.clear(); -} -//------------------------------------------------------------------------------ - -bool IntersectListSort(IntersectNode* node1, IntersectNode* node2) -{ - return node2->Pt.Y < node1->Pt.Y; -} -//------------------------------------------------------------------------------ - -inline bool EdgesAdjacent(const IntersectNode &inode) -{ - return (inode.Edge1->NextInSEL == inode.Edge2) || - (inode.Edge1->PrevInSEL == inode.Edge2); -} -//------------------------------------------------------------------------------ - -bool Clipper::FixupIntersectionOrder() -{ - //pre-condition: intersections are sorted Bottom-most first. - //Now it's crucial that intersections are made only between adjacent edges, - //so to ensure this the order of intersections may need adjusting ... - CopyAELToSEL(); - std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort); - size_t cnt = m_IntersectList.size(); - for (size_t i = 0; i < cnt; ++i) - { - if (!EdgesAdjacent(*m_IntersectList[i])) - { - size_t j = i + 1; - while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++; - if (j == cnt) return false; - std::swap(m_IntersectList[i], m_IntersectList[j]); - } - SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2); - } - return true; -} -//------------------------------------------------------------------------------ - -void Clipper::DoMaxima(TEdge *e) -{ - TEdge* eMaxPair = GetMaximaPairEx(e); - if (!eMaxPair) - { - if (e->OutIdx >= 0) - AddOutPt(e, e->Top); - DeleteFromAEL(e); - return; - } - - TEdge* eNext = e->NextInAEL; - while(eNext && eNext != eMaxPair) - { - IntersectEdges(e, eNext, e->Top); - SwapPositionsInAEL(e, eNext); - eNext = e->NextInAEL; - } - - if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) - { - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } - else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) - { - if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top); - DeleteFromAEL(e); - DeleteFromAEL(eMaxPair); - } -#ifdef use_lines - else if (e->WindDelta == 0) - { - if (e->OutIdx >= 0) - { - AddOutPt(e, e->Top); - e->OutIdx = Unassigned; - } - DeleteFromAEL(e); - - if (eMaxPair->OutIdx >= 0) - { - AddOutPt(eMaxPair, e->Top); - eMaxPair->OutIdx = Unassigned; - } - DeleteFromAEL(eMaxPair); - } -#endif - else throw clipperException("DoMaxima error"); -} -//------------------------------------------------------------------------------ - -void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) -{ - TEdge* e = m_ActiveEdges; - while( e ) - { - //1. process maxima, treating them as if they're 'bent' horizontal edges, - // but exclude maxima with horizontal edges. nb: e can't be a horizontal. - bool IsMaximaEdge = IsMaxima(e, topY); - - if(IsMaximaEdge) - { - TEdge* eMaxPair = GetMaximaPairEx(e); - IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); - } - - if(IsMaximaEdge) - { - if (m_StrictSimple) m_Maxima.push_back(e->Top.X); - TEdge* ePrev = e->PrevInAEL; - DoMaxima(e); - if( !ePrev ) e = m_ActiveEdges; - else e = ePrev->NextInAEL; - } - else - { - //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... - if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) - { - UpdateEdgeIntoAEL(e); - if (e->OutIdx >= 0) - AddOutPt(e, e->Bot); - AddEdgeToSEL(e); - } - else - { - e->Curr.X = TopX( *e, topY ); - e->Curr.Y = topY; -#ifdef use_xyz - e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0); -#endif - } - - //When StrictlySimple and 'e' is being touched by another edge, then - //make sure both edges have a vertex here ... - if (m_StrictSimple) - { - TEdge* ePrev = e->PrevInAEL; - if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && - (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0)) - { - IntPoint pt = e->Curr; -#ifdef use_xyz - SetZ(pt, *ePrev, *e); -#endif - OutPt* op = AddOutPt(ePrev, pt); - OutPt* op2 = AddOutPt(e, pt); - AddJoin(op, op2, pt); //StrictlySimple (type-3) join - } - } - - e = e->NextInAEL; - } - } - - //3. Process horizontals at the Top of the scanbeam ... - m_Maxima.sort(); - ProcessHorizontals(); - m_Maxima.clear(); - - //4. Promote intermediate vertices ... - e = m_ActiveEdges; - while(e) - { - if(IsIntermediate(e, topY)) - { - OutPt* op = 0; - if( e->OutIdx >= 0 ) - op = AddOutPt(e, e->Top); - UpdateEdgeIntoAEL(e); - - //if output polygons share an edge, they'll need joining later ... - TEdge* ePrev = e->PrevInAEL; - TEdge* eNext = e->NextInAEL; - if (ePrev && ePrev->Curr.X == e->Bot.X && - ePrev->Curr.Y == e->Bot.Y && op && - ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && - SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) && - (e->WindDelta != 0) && (ePrev->WindDelta != 0)) - { - OutPt* op2 = AddOutPt(ePrev, e->Bot); - AddJoin(op, op2, e->Top); - } - else if (eNext && eNext->Curr.X == e->Bot.X && - eNext->Curr.Y == e->Bot.Y && op && - eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && - SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) && - (e->WindDelta != 0) && (eNext->WindDelta != 0)) - { - OutPt* op2 = AddOutPt(eNext, e->Bot); - AddJoin(op, op2, e->Top); - } - } - e = e->NextInAEL; - } -} -//------------------------------------------------------------------------------ - -void Clipper::FixupOutPolyline(OutRec &outrec) -{ - OutPt *pp = outrec.Pts; - OutPt *lastPP = pp->Prev; - while (pp != lastPP) - { - pp = pp->Next; - if (pp->Pt == pp->Prev->Pt) - { - if (pp == lastPP) lastPP = pp->Prev; - OutPt *tmpPP = pp->Prev; - tmpPP->Next = pp->Next; - pp->Next->Prev = tmpPP; - delete pp; - pp = tmpPP; - } - } - - if (pp == pp->Prev) - { - DisposeOutPts(pp); - outrec.Pts = 0; - return; - } -} -//------------------------------------------------------------------------------ - -void Clipper::FixupOutPolygon(OutRec &outrec) -{ - //FixupOutPolygon() - removes duplicate points and simplifies consecutive - //parallel edges by removing the middle vertex. - OutPt *lastOK = 0; - outrec.BottomPt = 0; - OutPt *pp = outrec.Pts; - bool preserveCol = m_PreserveCollinear || m_StrictSimple; - - for (;;) - { - if (pp->Prev == pp || pp->Prev == pp->Next) - { - DisposeOutPts(pp); - outrec.Pts = 0; - return; - } - - //test for duplicate points and collinear edges ... - if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || - (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && - (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) - { - lastOK = 0; - OutPt *tmp = pp; - pp->Prev->Next = pp->Next; - pp->Next->Prev = pp->Prev; - pp = pp->Prev; - delete tmp; - } - else if (pp == lastOK) break; - else - { - if (!lastOK) lastOK = pp; - pp = pp->Next; - } - } - outrec.Pts = pp; -} -//------------------------------------------------------------------------------ - -int PointCount(OutPt *Pts) -{ - if (!Pts) return 0; - int result = 0; - OutPt* p = Pts; - do - { - result++; - p = p->Next; - } - while (p != Pts); - return result; -} -//------------------------------------------------------------------------------ - -void Clipper::BuildResult(Paths &polys) -{ - polys.reserve(m_PolyOuts.size()); - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - if (!m_PolyOuts[i]->Pts) continue; - Path pg; - OutPt* p = m_PolyOuts[i]->Pts->Prev; - int cnt = PointCount(p); - if (cnt < 2) continue; - pg.reserve(cnt); - for (int i = 0; i < cnt; ++i) - { - pg.push_back(p->Pt); - p = p->Prev; - } - polys.push_back(pg); - } -} -//------------------------------------------------------------------------------ - -void Clipper::BuildResult2(PolyTree& polytree) -{ - polytree.Clear(); - polytree.AllNodes.reserve(m_PolyOuts.size()); - //add each output polygon/contour to polytree ... - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) - { - OutRec* outRec = m_PolyOuts[i]; - int cnt = PointCount(outRec->Pts); - if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue; - FixHoleLinkage(*outRec); - PolyNode* pn = new PolyNode(); - //nb: polytree takes ownership of all the PolyNodes - polytree.AllNodes.push_back(pn); - outRec->PolyNd = pn; - pn->Parent = 0; - pn->Index = 0; - pn->Contour.reserve(cnt); - OutPt *op = outRec->Pts->Prev; - for (int j = 0; j < cnt; j++) - { - pn->Contour.push_back(op->Pt); - op = op->Prev; - } - } - - //fixup PolyNode links etc ... - polytree.Childs.reserve(m_PolyOuts.size()); - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) - { - OutRec* outRec = m_PolyOuts[i]; - if (!outRec->PolyNd) continue; - if (outRec->IsOpen) - { - outRec->PolyNd->m_IsOpen = true; - polytree.AddChild(*outRec->PolyNd); - } - else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd) - outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd); - else - polytree.AddChild(*outRec->PolyNd); - } -} -//------------------------------------------------------------------------------ - -void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) -{ - //just swap the contents (because fIntersectNodes is a single-linked-list) - IntersectNode inode = int1; //gets a copy of Int1 - int1.Edge1 = int2.Edge1; - int1.Edge2 = int2.Edge2; - int1.Pt = int2.Pt; - int2.Edge1 = inode.Edge1; - int2.Edge2 = inode.Edge2; - int2.Pt = inode.Pt; -} -//------------------------------------------------------------------------------ - -inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) -{ - if (e2.Curr.X == e1.Curr.X) - { - if (e2.Top.Y > e1.Top.Y) - return e2.Top.X < TopX(e1, e2.Top.Y); - else return e1.Top.X > TopX(e2, e1.Top.Y); - } - else return e2.Curr.X < e1.Curr.X; -} -//------------------------------------------------------------------------------ - -bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, - cInt& Left, cInt& Right) -{ - if (a1 < a2) - { - if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} - else {Left = std::max(a1,b2); Right = std::min(a2,b1);} - } - else - { - if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} - else {Left = std::max(a2,b2); Right = std::min(a1,b1);} - } - return Left < Right; -} -//------------------------------------------------------------------------------ - -inline void UpdateOutPtIdxs(OutRec& outrec) -{ - OutPt* op = outrec.Pts; - do - { - op->Idx = outrec.Idx; - op = op->Prev; - } - while(op != outrec.Pts); -} -//------------------------------------------------------------------------------ - -void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) -{ - if(!m_ActiveEdges) - { - edge->PrevInAEL = 0; - edge->NextInAEL = 0; - m_ActiveEdges = edge; - } - else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) - { - edge->PrevInAEL = 0; - edge->NextInAEL = m_ActiveEdges; - m_ActiveEdges->PrevInAEL = edge; - m_ActiveEdges = edge; - } - else - { - if(!startEdge) startEdge = m_ActiveEdges; - while(startEdge->NextInAEL && - !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) - startEdge = startEdge->NextInAEL; - edge->NextInAEL = startEdge->NextInAEL; - if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; - edge->PrevInAEL = startEdge; - startEdge->NextInAEL = edge; - } -} -//---------------------------------------------------------------------- - -OutPt* DupOutPt(OutPt* outPt, bool InsertAfter) -{ - OutPt* result = new OutPt; - result->Pt = outPt->Pt; - result->Idx = outPt->Idx; - if (InsertAfter) - { - result->Next = outPt->Next; - result->Prev = outPt; - outPt->Next->Prev = result; - outPt->Next = result; - } - else - { - result->Prev = outPt->Prev; - result->Next = outPt; - outPt->Prev->Next = result; - outPt->Prev = result; - } - return result; -} -//------------------------------------------------------------------------------ - -bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, - const IntPoint Pt, bool DiscardLeft) -{ - Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight); - Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight); - if (Dir1 == Dir2) return false; - - //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we - //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) - //So, to facilitate this while inserting Op1b and Op2b ... - //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, - //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) - if (Dir1 == dLeftToRight) - { - while (op1->Next->Pt.X <= Pt.X && - op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) - op1 = op1->Next; - if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; - op1b = DupOutPt(op1, !DiscardLeft); - if (op1b->Pt != Pt) - { - op1 = op1b; - op1->Pt = Pt; - op1b = DupOutPt(op1, !DiscardLeft); - } - } - else - { - while (op1->Next->Pt.X >= Pt.X && - op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) - op1 = op1->Next; - if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; - op1b = DupOutPt(op1, DiscardLeft); - if (op1b->Pt != Pt) - { - op1 = op1b; - op1->Pt = Pt; - op1b = DupOutPt(op1, DiscardLeft); - } - } - - if (Dir2 == dLeftToRight) - { - while (op2->Next->Pt.X <= Pt.X && - op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) - op2 = op2->Next; - if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; - op2b = DupOutPt(op2, !DiscardLeft); - if (op2b->Pt != Pt) - { - op2 = op2b; - op2->Pt = Pt; - op2b = DupOutPt(op2, !DiscardLeft); - }; - } else - { - while (op2->Next->Pt.X >= Pt.X && - op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) - op2 = op2->Next; - if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; - op2b = DupOutPt(op2, DiscardLeft); - if (op2b->Pt != Pt) - { - op2 = op2b; - op2->Pt = Pt; - op2b = DupOutPt(op2, DiscardLeft); - }; - }; - - if ((Dir1 == dLeftToRight) == DiscardLeft) - { - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - } - else - { - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - } - return true; -} -//------------------------------------------------------------------------------ - -bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) -{ - OutPt *op1 = j->OutPt1, *op1b; - OutPt *op2 = j->OutPt2, *op2b; - - //There are 3 kinds of joins for output polygons ... - //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere - //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). - //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same - //location at the Bottom of the overlapping segment (& Join.OffPt is above). - //3. StrictSimple joins where edges touch but are not collinear and where - //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. - bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y); - - if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && - (j->OffPt == j->OutPt2->Pt)) - { - //Strictly Simple join ... - if (outRec1 != outRec2) return false; - op1b = j->OutPt1->Next; - while (op1b != op1 && (op1b->Pt == j->OffPt)) - op1b = op1b->Next; - bool reverse1 = (op1b->Pt.Y > j->OffPt.Y); - op2b = j->OutPt2->Next; - while (op2b != op2 && (op2b->Pt == j->OffPt)) - op2b = op2b->Next; - bool reverse2 = (op2b->Pt.Y > j->OffPt.Y); - if (reverse1 == reverse2) return false; - if (reverse1) - { - op1b = DupOutPt(op1, false); - op2b = DupOutPt(op2, true); - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } else - { - op1b = DupOutPt(op1, true); - op2b = DupOutPt(op2, false); - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } - } - else if (isHorizontal) - { - //treat horizontal joins differently to non-horizontal joins since with - //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt - //may be anywhere along the horizontal edge. - op1b = op1; - while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2) - op1 = op1->Prev; - while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2) - op1b = op1b->Next; - if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' - - op2b = op2; - while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b) - op2 = op2->Prev; - while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1) - op2b = op2b->Next; - if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' - - cInt Left, Right; - //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges - if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right)) - return false; - - //DiscardLeftSide: when overlapping edges are joined, a spike will created - //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up - //on the discard Side as either may still be needed for other joins ... - IntPoint Pt; - bool DiscardLeftSide; - if (op1->Pt.X >= Left && op1->Pt.X <= Right) - { - Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X); - } - else if (op2->Pt.X >= Left&& op2->Pt.X <= Right) - { - Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X); - } - else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) - { - Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X; - } - else - { - Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X); - } - j->OutPt1 = op1; j->OutPt2 = op2; - return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); - } else - { - //nb: For non-horizontal joins ... - // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y - // 2. Jr.OutPt1.Pt > Jr.OffPt.Y - - //make sure the polygons are correctly oriented ... - op1b = op1->Next; - while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; - bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) || - !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); - if (Reverse1) - { - op1b = op1->Prev; - while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; - if ((op1b->Pt.Y > op1->Pt.Y) || - !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; - }; - op2b = op2->Next; - while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; - bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) || - !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); - if (Reverse2) - { - op2b = op2->Prev; - while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; - if ((op2b->Pt.Y > op2->Pt.Y) || - !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; - } - - if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || - ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; - - if (Reverse1) - { - op1b = DupOutPt(op1, false); - op2b = DupOutPt(op2, true); - op1->Prev = op2; - op2->Next = op1; - op1b->Next = op2b; - op2b->Prev = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } else - { - op1b = DupOutPt(op1, true); - op2b = DupOutPt(op2, false); - op1->Next = op2; - op2->Prev = op1; - op1b->Prev = op2b; - op2b->Next = op1b; - j->OutPt1 = op1; - j->OutPt2 = op1b; - return true; - } - } -} -//---------------------------------------------------------------------- - -static OutRec* ParseFirstLeft(OutRec* FirstLeft) -{ - while (FirstLeft && !FirstLeft->Pts) - FirstLeft = FirstLeft->FirstLeft; - return FirstLeft; -} -//------------------------------------------------------------------------------ - -void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) -{ - //tests if NewOutRec contains the polygon before reassigning FirstLeft - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - OutRec* outRec = m_PolyOuts[i]; - OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); - if (outRec->Pts && firstLeft == OldOutRec) - { - if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) - outRec->FirstLeft = NewOutRec; - } - } -} -//---------------------------------------------------------------------- - -void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec) -{ - //A polygon has split into two such that one is now the inner of the other. - //It's possible that these polygons now wrap around other polygons, so check - //every polygon that's also contained by OuterOutRec's FirstLeft container - //(including 0) to see if they've become inner to the new inner polygon ... - OutRec* orfl = OuterOutRec->FirstLeft; - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - OutRec* outRec = m_PolyOuts[i]; - - if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec) - continue; - OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); - if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec) - continue; - if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts)) - outRec->FirstLeft = InnerOutRec; - else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts)) - outRec->FirstLeft = OuterOutRec; - else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec) - outRec->FirstLeft = orfl; - } -} -//---------------------------------------------------------------------- -void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec) -{ - //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon - for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) - { - OutRec* outRec = m_PolyOuts[i]; - OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); - if (outRec->Pts && firstLeft == OldOutRec) - outRec->FirstLeft = NewOutRec; - } -} -//---------------------------------------------------------------------- - -void Clipper::JoinCommonEdges() -{ - for (JoinList::size_type i = 0; i < m_Joins.size(); i++) - { - Join* join = m_Joins[i]; - - OutRec *outRec1 = GetOutRec(join->OutPt1->Idx); - OutRec *outRec2 = GetOutRec(join->OutPt2->Idx); - - if (!outRec1->Pts || !outRec2->Pts) continue; - if (outRec1->IsOpen || outRec2->IsOpen) continue; - - //get the polygon fragment with the correct hole state (FirstLeft) - //before calling JoinPoints() ... - OutRec *holeStateRec; - if (outRec1 == outRec2) holeStateRec = outRec1; - else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2; - else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1; - else holeStateRec = GetLowermostRec(outRec1, outRec2); - - if (!JoinPoints(join, outRec1, outRec2)) continue; - - if (outRec1 == outRec2) - { - //instead of joining two polygons, we've just created a new one by - //splitting one polygon into two. - outRec1->Pts = join->OutPt1; - outRec1->BottomPt = 0; - outRec2 = CreateOutRec(); - outRec2->Pts = join->OutPt2; - - //update all OutRec2.Pts Idx's ... - UpdateOutPtIdxs(*outRec2); - - if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) - { - //outRec1 contains outRec2 ... - outRec2->IsHole = !outRec1->IsHole; - outRec2->FirstLeft = outRec1; - - if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); - - if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) - ReversePolyPtLinks(outRec2->Pts); - - } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) - { - //outRec2 contains outRec1 ... - outRec2->IsHole = outRec1->IsHole; - outRec1->IsHole = !outRec2->IsHole; - outRec2->FirstLeft = outRec1->FirstLeft; - outRec1->FirstLeft = outRec2; - - if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); - - if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) - ReversePolyPtLinks(outRec1->Pts); - } - else - { - //the 2 polygons are completely separate ... - outRec2->IsHole = outRec1->IsHole; - outRec2->FirstLeft = outRec1->FirstLeft; - - //fixup FirstLeft pointers that may need reassigning to OutRec2 - if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); - } - - } else - { - //joined 2 polygons together ... - - outRec2->Pts = 0; - outRec2->BottomPt = 0; - outRec2->Idx = outRec1->Idx; - - outRec1->IsHole = holeStateRec->IsHole; - if (holeStateRec == outRec2) - outRec1->FirstLeft = outRec2->FirstLeft; - outRec2->FirstLeft = outRec1; - - if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1); - } - } -} - -//------------------------------------------------------------------------------ -// ClipperOffset support functions ... -//------------------------------------------------------------------------------ - -DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) -{ - if(pt2.X == pt1.X && pt2.Y == pt1.Y) - return DoublePoint(0, 0); - - double Dx = (double)(pt2.X - pt1.X); - double dy = (double)(pt2.Y - pt1.Y); - double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy ); - Dx *= f; - dy *= f; - return DoublePoint(dy, -Dx); -} - -//------------------------------------------------------------------------------ -// ClipperOffset class -//------------------------------------------------------------------------------ - -ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) -{ - this->MiterLimit = miterLimit; - this->ArcTolerance = arcTolerance; - m_lowest.X = -1; -} -//------------------------------------------------------------------------------ - -ClipperOffset::~ClipperOffset() -{ - Clear(); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::Clear() -{ - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - delete m_polyNodes.Childs[i]; - m_polyNodes.Childs.clear(); - m_lowest.X = -1; -} -//------------------------------------------------------------------------------ - -void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) -{ - int highI = (int)path.size() - 1; - if (highI < 0) return; - PolyNode* newNode = new PolyNode(); - newNode->m_jointype = joinType; - newNode->m_endtype = endType; - - //strip duplicate points from path and also get index to the lowest point ... - if (endType == etClosedLine || endType == etClosedPolygon) - while (highI > 0 && path[0] == path[highI]) highI--; - newNode->Contour.reserve(highI + 1); - newNode->Contour.push_back(path[0]); - int j = 0, k = 0; - for (int i = 1; i <= highI; i++) - if (newNode->Contour[j] != path[i]) - { - j++; - newNode->Contour.push_back(path[i]); - if (path[i].Y > newNode->Contour[k].Y || - (path[i].Y == newNode->Contour[k].Y && - path[i].X < newNode->Contour[k].X)) k = j; - } - if (endType == etClosedPolygon && j < 2) - { - delete newNode; - return; - } - m_polyNodes.AddChild(*newNode); - - //if this path's lowest pt is lower than all the others then update m_lowest - if (endType != etClosedPolygon) return; - if (m_lowest.X < 0) - m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); - else - { - IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y]; - if (newNode->Contour[k].Y > ip.Y || - (newNode->Contour[k].Y == ip.Y && - newNode->Contour[k].X < ip.X)) - m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) -{ - for (Paths::size_type i = 0; i < paths.size(); ++i) - AddPath(paths[i], joinType, endType); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::FixOrientations() -{ - //fixup orientations of all closed paths if the orientation of the - //closed path with the lowermost vertex is wrong ... - if (m_lowest.X >= 0 && - !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) - { - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedPolygon || - (node.m_endtype == etClosedLine && Orientation(node.Contour))) - ReversePath(node.Contour); - } - } else - { - for (int i = 0; i < m_polyNodes.ChildCount(); ++i) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) - ReversePath(node.Contour); - } - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::Execute(Paths& solution, double delta) -{ - solution.clear(); - FixOrientations(); - DoOffset(delta); - - //now clean up 'corners' ... - Clipper clpr; - clpr.AddPaths(m_destPolys, ptSubject, true); - if (delta > 0) - { - clpr.Execute(ctUnion, solution, pftPositive, pftPositive); - } - else - { - IntRect r = clpr.GetBounds(); - Path outer(4); - outer[0] = IntPoint(r.left - 10, r.bottom + 10); - outer[1] = IntPoint(r.right + 10, r.bottom + 10); - outer[2] = IntPoint(r.right + 10, r.top - 10); - outer[3] = IntPoint(r.left - 10, r.top - 10); - - clpr.AddPath(outer, ptSubject, true); - clpr.ReverseSolution(true); - clpr.Execute(ctUnion, solution, pftNegative, pftNegative); - if (solution.size() > 0) solution.erase(solution.begin()); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::Execute(PolyTree& solution, double delta) -{ - solution.Clear(); - FixOrientations(); - DoOffset(delta); - - //now clean up 'corners' ... - Clipper clpr; - clpr.AddPaths(m_destPolys, ptSubject, true); - if (delta > 0) - { - clpr.Execute(ctUnion, solution, pftPositive, pftPositive); - } - else - { - IntRect r = clpr.GetBounds(); - Path outer(4); - outer[0] = IntPoint(r.left - 10, r.bottom + 10); - outer[1] = IntPoint(r.right + 10, r.bottom + 10); - outer[2] = IntPoint(r.right + 10, r.top - 10); - outer[3] = IntPoint(r.left - 10, r.top - 10); - - clpr.AddPath(outer, ptSubject, true); - clpr.ReverseSolution(true); - clpr.Execute(ctUnion, solution, pftNegative, pftNegative); - //remove the outer PolyNode rectangle ... - if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) - { - PolyNode* outerNode = solution.Childs[0]; - solution.Childs.reserve(outerNode->ChildCount()); - solution.Childs[0] = outerNode->Childs[0]; - solution.Childs[0]->Parent = outerNode->Parent; - for (int i = 1; i < outerNode->ChildCount(); ++i) - solution.AddChild(*outerNode->Childs[i]); - } - else - solution.Clear(); - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoOffset(double delta) -{ - m_destPolys.clear(); - m_delta = delta; - - //if Zero offset, just copy any CLOSED polygons to m_p and return ... - if (NEAR_ZERO(delta)) - { - m_destPolys.reserve(m_polyNodes.ChildCount()); - for (int i = 0; i < m_polyNodes.ChildCount(); i++) - { - PolyNode& node = *m_polyNodes.Childs[i]; - if (node.m_endtype == etClosedPolygon) - m_destPolys.push_back(node.Contour); - } - return; - } - - //see offset_triginometry3.svg in the documentation folder ... - if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit); - else m_miterLim = 0.5; - - double y; - if (ArcTolerance <= 0.0) y = def_arc_tolerance; - else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) - y = std::fabs(delta) * def_arc_tolerance; - else y = ArcTolerance; - //see offset_triginometry2.svg in the documentation folder ... - double steps = pi / std::acos(1 - y / std::fabs(delta)); - if (steps > std::fabs(delta) * pi) - steps = std::fabs(delta) * pi; //ie excessive precision check - m_sin = std::sin(two_pi / steps); - m_cos = std::cos(two_pi / steps); - m_StepsPerRad = steps / two_pi; - if (delta < 0.0) m_sin = -m_sin; - - m_destPolys.reserve(m_polyNodes.ChildCount() * 2); - for (int i = 0; i < m_polyNodes.ChildCount(); i++) - { - PolyNode& node = *m_polyNodes.Childs[i]; - m_srcPoly = node.Contour; - - int len = (int)m_srcPoly.size(); - if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) - continue; - - m_destPoly.clear(); - if (len == 1) - { - if (node.m_jointype == jtRound) - { - double X = 1.0, Y = 0.0; - for (cInt j = 1; j <= steps; j++) - { - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[0].X + X * delta), - Round(m_srcPoly[0].Y + Y * delta))); - double X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - } - else - { - double X = -1.0, Y = -1.0; - for (int j = 0; j < 4; ++j) - { - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[0].X + X * delta), - Round(m_srcPoly[0].Y + Y * delta))); - if (X < 0) X = 1; - else if (Y < 0) Y = 1; - else X = -1; - } - } - m_destPolys.push_back(m_destPoly); - continue; - } - //build m_normals ... - m_normals.clear(); - m_normals.reserve(len); - for (int j = 0; j < len - 1; ++j) - m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); - if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) - m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); - else - m_normals.push_back(DoublePoint(m_normals[len - 2])); - - if (node.m_endtype == etClosedPolygon) - { - int k = len - 1; - for (int j = 0; j < len; ++j) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.push_back(m_destPoly); - } - else if (node.m_endtype == etClosedLine) - { - int k = len - 1; - for (int j = 0; j < len; ++j) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.push_back(m_destPoly); - m_destPoly.clear(); - //re-build m_normals ... - DoublePoint n = m_normals[len -1]; - for (int j = len - 1; j > 0; j--) - m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); - m_normals[0] = DoublePoint(-n.X, -n.Y); - k = 0; - for (int j = len - 1; j >= 0; j--) - OffsetPoint(j, k, node.m_jointype); - m_destPolys.push_back(m_destPoly); - } - else - { - int k = 0; - for (int j = 1; j < len - 1; ++j) - OffsetPoint(j, k, node.m_jointype); - - IntPoint pt1; - if (node.m_endtype == etOpenButt) - { - int j = len - 1; - pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * - delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); - m_destPoly.push_back(pt1); - pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * - delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); - m_destPoly.push_back(pt1); - } - else - { - int j = len - 1; - k = len - 2; - m_sinA = 0; - m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y); - if (node.m_endtype == etOpenSquare) - DoSquare(j, k); - else - DoRound(j, k); - } - - //re-build m_normals ... - for (int j = len - 1; j > 0; j--) - m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); - m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y); - - k = len - 1; - for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); - - if (node.m_endtype == etOpenButt) - { - pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), - (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); - m_destPoly.push_back(pt1); - pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), - (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); - m_destPoly.push_back(pt1); - } - else - { - k = 1; - m_sinA = 0; - if (node.m_endtype == etOpenSquare) - DoSquare(0, 1); - else - DoRound(0, 1); - } - m_destPolys.push_back(m_destPoly); - } - } -} -//------------------------------------------------------------------------------ - -void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) -{ - //cross product ... - m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); - if (std::fabs(m_sinA * m_delta) < 1.0) - { - //dot product ... - double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y ); - if (cosA > 0) // angle => 0 degrees - { - m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); - return; - } - //else angle => 180 degrees - } - else if (m_sinA > 1.0) m_sinA = 1.0; - else if (m_sinA < -1.0) m_sinA = -1.0; - - if (m_sinA * m_delta < 0) - { - m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); - m_destPoly.push_back(m_srcPoly[j]); - m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); - } - else - switch (jointype) - { - case jtMiter: - { - double r = 1 + (m_normals[j].X * m_normals[k].X + - m_normals[j].Y * m_normals[k].Y); - if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); - break; - } - case jtSquare: DoSquare(j, k); break; - case jtRound: DoRound(j, k); break; - } - k = j; -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoSquare(int j, int k) -{ - double dx = std::tan(std::atan2(m_sinA, - m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), - Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), - Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoMiter(int j, int k, double r) -{ - double q = m_delta / r; - m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), - Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); -} -//------------------------------------------------------------------------------ - -void ClipperOffset::DoRound(int j, int k) -{ - double a = std::atan2(m_sinA, - m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); - int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1); - - double X = m_normals[k].X, Y = m_normals[k].Y, X2; - for (int i = 0; i < steps; ++i) - { - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[j].X + X * m_delta), - Round(m_srcPoly[j].Y + Y * m_delta))); - X2 = X; - X = X * m_cos - m_sin * Y; - Y = X2 * m_sin + Y * m_cos; - } - m_destPoly.push_back(IntPoint( - Round(m_srcPoly[j].X + m_normals[j].X * m_delta), - Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); -} - -//------------------------------------------------------------------------------ -// Miscellaneous public functions -//------------------------------------------------------------------------------ - -void Clipper::DoSimplePolygons() -{ - PolyOutList::size_type i = 0; - while (i < m_PolyOuts.size()) - { - OutRec* outrec = m_PolyOuts[i++]; - OutPt* op = outrec->Pts; - if (!op || outrec->IsOpen) continue; - do //for each Pt in Polygon until duplicate found do ... - { - OutPt* op2 = op->Next; - while (op2 != outrec->Pts) - { - if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) - { - //split the polygon into two ... - OutPt* op3 = op->Prev; - OutPt* op4 = op2->Prev; - op->Prev = op4; - op4->Next = op; - op2->Prev = op3; - op3->Next = op2; - - outrec->Pts = op; - OutRec* outrec2 = CreateOutRec(); - outrec2->Pts = op2; - UpdateOutPtIdxs(*outrec2); - if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) - { - //OutRec2 is contained by OutRec1 ... - outrec2->IsHole = !outrec->IsHole; - outrec2->FirstLeft = outrec; - if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec); - } - else - if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) - { - //OutRec1 is contained by OutRec2 ... - outrec2->IsHole = outrec->IsHole; - outrec->IsHole = !outrec2->IsHole; - outrec2->FirstLeft = outrec->FirstLeft; - outrec->FirstLeft = outrec2; - if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2); - } - else - { - //the 2 polygons are separate ... - outrec2->IsHole = outrec->IsHole; - outrec2->FirstLeft = outrec->FirstLeft; - if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2); - } - op2 = op; //ie get ready for the Next iteration - } - op2 = op2->Next; - } - op = op->Next; - } - while (op != outrec->Pts); - } -} -//------------------------------------------------------------------------------ - -void ReversePath(Path& p) -{ - std::reverse(p.begin(), p.end()); -} -//------------------------------------------------------------------------------ - -void ReversePaths(Paths& p) -{ - for (Paths::size_type i = 0; i < p.size(); ++i) - ReversePath(p[i]); -} -//------------------------------------------------------------------------------ - -void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) -{ - Clipper c; - c.StrictlySimple(true); - c.AddPath(in_poly, ptSubject, true); - c.Execute(ctUnion, out_polys, fillType, fillType); -} -//------------------------------------------------------------------------------ - -void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) -{ - Clipper c; - c.StrictlySimple(true); - c.AddPaths(in_polys, ptSubject, true); - c.Execute(ctUnion, out_polys, fillType, fillType); -} -//------------------------------------------------------------------------------ - -void SimplifyPolygons(Paths &polys, PolyFillType fillType) -{ - SimplifyPolygons(polys, polys, fillType); -} -//------------------------------------------------------------------------------ - -inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) -{ - double Dx = ((double)pt1.X - pt2.X); - double dy = ((double)pt1.Y - pt2.Y); - return (Dx*Dx + dy*dy); -} -//------------------------------------------------------------------------------ - -double DistanceFromLineSqrd( - const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) -{ - //The equation of a line in general form (Ax + By + C = 0) - //given 2 points (x¹,y¹) & (x²,y²) is ... - //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0 - //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹ - //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²) - //see http://en.wikipedia.org/wiki/Perpendicular_distance - double A = double(ln1.Y - ln2.Y); - double B = double(ln2.X - ln1.X); - double C = A * ln1.X + B * ln1.Y; - C = A * pt.X + B * pt.Y - C; - return (C * C) / (A * A + B * B); -} -//--------------------------------------------------------------------------- - -bool SlopesNearCollinear(const IntPoint& pt1, - const IntPoint& pt2, const IntPoint& pt3, double distSqrd) -{ - //this function is more accurate when the point that's geometrically - //between the other 2 points is the one that's tested for distance. - //ie makes it more likely to pick up 'spikes' ... - if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y)) - { - if ((pt1.X > pt2.X) == (pt1.X < pt3.X)) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.X > pt1.X) == (pt2.X < pt3.X)) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } - else - { - if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y)) - return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; - else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y)) - return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; - else - return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; - } -} -//------------------------------------------------------------------------------ - -bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) -{ - double Dx = (double)pt1.X - pt2.X; - double dy = (double)pt1.Y - pt2.Y; - return ((Dx * Dx) + (dy * dy) <= distSqrd); -} -//------------------------------------------------------------------------------ - -OutPt* ExcludeOp(OutPt* op) -{ - OutPt* result = op->Prev; - result->Next = op->Next; - op->Next->Prev = result; - result->Idx = 0; - return result; -} -//------------------------------------------------------------------------------ - -void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) -{ - //distance = proximity in units/pixels below which vertices - //will be stripped. Default ~= sqrt(2). - - size_t size = in_poly.size(); - - if (size == 0) - { - out_poly.clear(); - return; - } - - OutPt* outPts = new OutPt[size]; - for (size_t i = 0; i < size; ++i) - { - outPts[i].Pt = in_poly[i]; - outPts[i].Next = &outPts[(i + 1) % size]; - outPts[i].Next->Prev = &outPts[i]; - outPts[i].Idx = 0; - } - - double distSqrd = distance * distance; - OutPt* op = &outPts[0]; - while (op->Idx == 0 && op->Next != op->Prev) - { - if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) - { - op = ExcludeOp(op); - size--; - } - else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) - { - ExcludeOp(op->Next); - op = ExcludeOp(op); - size -= 2; - } - else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) - { - op = ExcludeOp(op); - size--; - } - else - { - op->Idx = 1; - op = op->Next; - } - } - - if (size < 3) size = 0; - out_poly.resize(size); - for (size_t i = 0; i < size; ++i) - { - out_poly[i] = op->Pt; - op = op->Next; - } - delete [] outPts; -} -//------------------------------------------------------------------------------ - -void CleanPolygon(Path& poly, double distance) -{ - CleanPolygon(poly, poly, distance); -} -//------------------------------------------------------------------------------ - -void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) -{ - out_polys.resize(in_polys.size()); - for (Paths::size_type i = 0; i < in_polys.size(); ++i) - CleanPolygon(in_polys[i], out_polys[i], distance); -} -//------------------------------------------------------------------------------ - -void CleanPolygons(Paths& polys, double distance) -{ - CleanPolygons(polys, polys, distance); -} -//------------------------------------------------------------------------------ - -void Minkowski(const Path& poly, const Path& path, - Paths& solution, bool isSum, bool isClosed) -{ - int delta = (isClosed ? 1 : 0); - size_t polyCnt = poly.size(); - size_t pathCnt = path.size(); - Paths pp; - pp.reserve(pathCnt); - if (isSum) - for (size_t i = 0; i < pathCnt; ++i) - { - Path p; - p.reserve(polyCnt); - for (size_t j = 0; j < poly.size(); ++j) - p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y)); - pp.push_back(p); - } - else - for (size_t i = 0; i < pathCnt; ++i) - { - Path p; - p.reserve(polyCnt); - for (size_t j = 0; j < poly.size(); ++j) - p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y)); - pp.push_back(p); - } - - solution.clear(); - solution.reserve((pathCnt + delta) * (polyCnt + 1)); - for (size_t i = 0; i < pathCnt - 1 + delta; ++i) - for (size_t j = 0; j < polyCnt; ++j) - { - Path quad; - quad.reserve(4); - quad.push_back(pp[i % pathCnt][j % polyCnt]); - quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]); - quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); - quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]); - if (!Orientation(quad)) ReversePath(quad); - solution.push_back(quad); - } -} -//------------------------------------------------------------------------------ - -void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) -{ - Minkowski(pattern, path, solution, true, pathIsClosed); - Clipper c; - c.AddPaths(solution, ptSubject, true); - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -void TranslatePath(const Path& input, Path& output, const IntPoint delta) -{ - //precondition: input != output - output.resize(input.size()); - for (size_t i = 0; i < input.size(); ++i) - output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y); -} -//------------------------------------------------------------------------------ - -void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed) -{ - Clipper c; - for (size_t i = 0; i < paths.size(); ++i) - { - Paths tmp; - Minkowski(pattern, paths[i], tmp, true, pathIsClosed); - c.AddPaths(tmp, ptSubject, true); - if (pathIsClosed) - { - Path tmp2; - TranslatePath(paths[i], tmp2, pattern[0]); - c.AddPath(tmp2, ptClip, true); - } - } - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) -{ - Minkowski(poly1, poly2, solution, false, true); - Clipper c; - c.AddPaths(solution, ptSubject, true); - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); -} -//------------------------------------------------------------------------------ - -enum NodeType {ntAny, ntOpen, ntClosed}; - -void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths) -{ - bool match = true; - if (nodetype == ntClosed) match = !polynode.IsOpen(); - else if (nodetype == ntOpen) return; - - if (!polynode.Contour.empty() && match) - paths.push_back(polynode.Contour); - for (int i = 0; i < polynode.ChildCount(); ++i) - AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths); -} -//------------------------------------------------------------------------------ - -void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) -{ - paths.resize(0); - paths.reserve(polytree.Total()); - AddPolyNodeToPaths(polytree, ntAny, paths); -} -//------------------------------------------------------------------------------ - -void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) -{ - paths.resize(0); - paths.reserve(polytree.Total()); - AddPolyNodeToPaths(polytree, ntClosed, paths); -} -//------------------------------------------------------------------------------ - -void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) -{ - paths.resize(0); - paths.reserve(polytree.Total()); - //Open paths are top level only, so ... - for (int i = 0; i < polytree.ChildCount(); ++i) - if (polytree.Childs[i]->IsOpen()) - paths.push_back(polytree.Childs[i]->Contour); -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const IntPoint &p) -{ - s << "(" << p.X << "," << p.Y << ")"; - return s; -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const Path &p) -{ - if (p.empty()) return s; - Path::size_type last = p.size() -1; - for (Path::size_type i = 0; i < last; i++) - s << "(" << p[i].X << "," << p[i].Y << "), "; - s << "(" << p[last].X << "," << p[last].Y << ")\n"; - return s; -} -//------------------------------------------------------------------------------ - -std::ostream& operator <<(std::ostream &s, const Paths &p) -{ - for (Paths::size_type i = 0; i < p.size(); i++) - s << p[i]; - s << "\n"; - return s; -} -//------------------------------------------------------------------------------ - -} //ClipperLib namespace +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.4.2 * +* Date : 27 February 2017 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2017 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +/******************************************************************************* +* * +* This is a translation of the Delphi Clipper library and the naming style * +* used has retained a Delphi flavour. * +* * +*******************************************************************************/ + +#include "clipper.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +static double const pi = 3.141592653589793238; +static double const two_pi = pi *2; +static double const def_arc_tolerance = 0.25; + +enum Direction { dRightToLeft, dLeftToRight }; + +static int const Unassigned = -1; //edge not currently 'owning' a solution +static int const Skip = -2; //edge that would otherwise close a path + +#define HORIZONTAL (-1.0E+40) +#define TOLERANCE (1.0e-20) +#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) + +struct TEdge { + IntPoint Bot; + IntPoint Curr; //current (updated for every new scanbeam) + IntPoint Top; + double Dx; + PolyType PolyTyp; + EdgeSide Side; //side only refers to current side of solution poly + int WindDelta; //1 or -1 depending on winding direction + int WindCnt; + int WindCnt2; //winding count of the opposite polytype + int OutIdx; + TEdge *Next; + TEdge *Prev; + TEdge *NextInLML; + TEdge *NextInAEL; + TEdge *PrevInAEL; + TEdge *NextInSEL; + TEdge *PrevInSEL; +}; + +struct IntersectNode { + TEdge *Edge1; + TEdge *Edge2; + IntPoint Pt; +}; + +struct LocalMinimum { + cInt Y; + TEdge *LeftBound; + TEdge *RightBound; +}; + +struct OutPt; + +//OutRec: contains a path in the clipping solution. Edges in the AEL will +//carry a pointer to an OutRec when they are part of the clipping solution. +struct OutRec { + int Idx; + bool IsHole; + bool IsOpen; + OutRec *FirstLeft; //see comments in clipper.pas + PolyNode *PolyNd; + OutPt *Pts; + OutPt *BottomPt; +}; + +struct OutPt { + int Idx; + IntPoint Pt; + OutPt *Next; + OutPt *Prev; +}; + +struct Join { + OutPt *OutPt1; + OutPt *OutPt2; + IntPoint OffPt; +}; + +struct LocMinSorter +{ + inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2) + { + return locMin2.Y < locMin1.Y; + } +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +inline cInt Round(double val) +{ + if ((val < 0)) return static_cast(val - 0.5); + else return static_cast(val + 0.5); +} +//------------------------------------------------------------------------------ + +inline cInt Abs(cInt val) +{ + return val < 0 ? -val : val; +} + +//------------------------------------------------------------------------------ +// PolyTree methods ... +//------------------------------------------------------------------------------ + +void PolyTree::Clear() +{ + for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) + delete AllNodes[i]; + AllNodes.resize(0); + Childs.resize(0); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyTree::GetFirst() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return 0; +} +//------------------------------------------------------------------------------ + +int PolyTree::Total() const +{ + int result = (int)AllNodes.size(); + //with negative offsets, ignore the hidden outer polygon ... + if (result > 0 && Childs[0] != AllNodes[0]) result--; + return result; +} + +//------------------------------------------------------------------------------ +// PolyNode methods ... +//------------------------------------------------------------------------------ + +PolyNode::PolyNode(): Parent(0), Index(0), m_IsOpen(false) +{ +} +//------------------------------------------------------------------------------ + +int PolyNode::ChildCount() const +{ + return (int)Childs.size(); +} +//------------------------------------------------------------------------------ + +void PolyNode::AddChild(PolyNode& child) +{ + unsigned cnt = (unsigned)Childs.size(); + Childs.push_back(&child); + child.Parent = this; + child.Index = cnt; +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNext() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return GetNextSiblingUp(); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNextSiblingUp() const +{ + if (!Parent) //protects against PolyTree.GetNextSiblingUp() + return 0; + else if (Index == Parent->Childs.size() - 1) + return Parent->GetNextSiblingUp(); + else + return Parent->Childs[Index + 1]; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsHole() const +{ + bool result = true; + PolyNode* node = Parent; + while (node) + { + result = !result; + node = node->Parent; + } + return result; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsOpen() const +{ + return m_IsOpen; +} +//------------------------------------------------------------------------------ + +#ifndef use_int32 + +//------------------------------------------------------------------------------ +// Int128 class (enables safe math on signed 64bit integers) +// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 +// Int128 val2((long64)9223372036854775807); +// Int128 val3 = val1 * val2; +// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) +//------------------------------------------------------------------------------ + +class Int128 +{ + public: + ulong64 lo; + long64 hi; + + Int128(long64 _lo = 0) + { + lo = (ulong64)_lo; + if (_lo < 0) hi = -1; else hi = 0; + } + + + Int128(const Int128 &val): lo(val.lo), hi(val.hi){} + + Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} + + Int128& operator = (const long64 &val) + { + lo = (ulong64)val; + if (val < 0) hi = -1; else hi = 0; + return *this; + } + + bool operator == (const Int128 &val) const + {return (hi == val.hi && lo == val.lo);} + + bool operator != (const Int128 &val) const + { return !(*this == val);} + + bool operator > (const Int128 &val) const + { + if (hi != val.hi) + return hi > val.hi; + else + return lo > val.lo; + } + + bool operator < (const Int128 &val) const + { + if (hi != val.hi) + return hi < val.hi; + else + return lo < val.lo; + } + + bool operator >= (const Int128 &val) const + { return !(*this < val);} + + bool operator <= (const Int128 &val) const + { return !(*this > val);} + + Int128& operator += (const Int128 &rhs) + { + hi += rhs.hi; + lo += rhs.lo; + if (lo < rhs.lo) hi++; + return *this; + } + + Int128 operator + (const Int128 &rhs) const + { + Int128 result(*this); + result+= rhs; + return result; + } + + Int128& operator -= (const Int128 &rhs) + { + *this += -rhs; + return *this; + } + + Int128 operator - (const Int128 &rhs) const + { + Int128 result(*this); + result -= rhs; + return result; + } + + Int128 operator-() const //unary negation + { + if (lo == 0) + return Int128(-hi, 0); + else + return Int128(~hi, ~lo + 1); + } + + operator double() const + { + const double shift64 = 18446744073709551616.0; //2^64 + if (hi < 0) + { + if (lo == 0) return (double)hi * shift64; + else return -(double)(~lo + ~hi * shift64); + } + else + return (double)(lo + hi * shift64); + } + +}; +//------------------------------------------------------------------------------ + +Int128 Int128Mul (long64 lhs, long64 rhs) +{ + bool negate = (lhs < 0) != (rhs < 0); + + if (lhs < 0) lhs = -lhs; + ulong64 int1Hi = ulong64(lhs) >> 32; + ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); + + if (rhs < 0) rhs = -rhs; + ulong64 int2Hi = ulong64(rhs) >> 32; + ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); + + //nb: see comments in clipper.pas + ulong64 a = int1Hi * int2Hi; + ulong64 b = int1Lo * int2Lo; + ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; + + Int128 tmp; + tmp.hi = long64(a + (c >> 32)); + tmp.lo = long64(c << 32); + tmp.lo += long64(b); + if (tmp.lo < b) tmp.hi++; + if (negate) tmp = -tmp; + return tmp; +}; +#endif + +//------------------------------------------------------------------------------ +// Miscellaneous global functions +//------------------------------------------------------------------------------ + +bool Orientation(const Path &poly) +{ + return Area(poly) >= 0; +} +//------------------------------------------------------------------------------ + +double Area(const Path &poly) +{ + int size = (int)poly.size(); + if (size < 3) return 0; + + double a = 0; + for (int i = 0, j = size -1; i < size; ++i) + { + a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y); + j = i; + } + return -a * 0.5; +} +//------------------------------------------------------------------------------ + +double Area(const OutPt *op) +{ + const OutPt *startOp = op; + if (!op) return 0; + double a = 0; + do { + a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y); + op = op->Next; + } while (op != startOp); + return a * 0.5; +} +//------------------------------------------------------------------------------ + +double Area(const OutRec &outRec) +{ + return Area(outRec.Pts); +} +//------------------------------------------------------------------------------ + +bool PointIsVertex(const IntPoint &Pt, OutPt *pp) +{ + OutPt *pp2 = pp; + do + { + if (pp2->Pt == Pt) return true; + pp2 = pp2->Next; + } + while (pp2 != pp); + return false; +} +//------------------------------------------------------------------------------ + +//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos +//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf +int PointInPolygon(const IntPoint &pt, const Path &path) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + int result = 0; + size_t cnt = path.size(); + if (cnt < 3) return 0; + IntPoint ip = path[0]; + for(size_t i = 1; i <= cnt; ++i) + { + IntPoint ipNext = (i == cnt ? path[0] : path[i]); + if (ipNext.Y == pt.Y) + { + if ((ipNext.X == pt.X) || (ip.Y == pt.Y && + ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1; + } + if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y)) + { + if (ip.X >= pt.X) + { + if (ipNext.X > pt.X) result = 1 - result; + else + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } else + { + if (ipNext.X > pt.X) + { + double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) - + (double)(ipNext.X - pt.X) * (ip.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result; + } + } + } + ip = ipNext; + } + return result; +} +//------------------------------------------------------------------------------ + +int PointInPolygon (const IntPoint &pt, OutPt *op) +{ + //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + int result = 0; + OutPt* startOp = op; + for(;;) + { + if (op->Next->Pt.Y == pt.Y) + { + if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y && + ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1; + } + if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y)) + { + if (op->Pt.X >= pt.X) + { + if (op->Next->Pt.X > pt.X) result = 1 - result; + else + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } else + { + if (op->Next->Pt.X > pt.X) + { + double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) - + (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y); + if (!d) return -1; + if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result; + } + } + } + op = op->Next; + if (startOp == op) break; + } + return result; +} +//------------------------------------------------------------------------------ + +bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2) +{ + OutPt* op = OutPt1; + do + { + //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon + int res = PointInPolygon(op->Pt, OutPt2); + if (res >= 0) return res > 0; + op = op->Next; + } + while (op != OutPt1); + return true; +} +//---------------------------------------------------------------------- + +bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) == + Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y); + else +#endif + return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) == + (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) +{ +#ifndef use_int32 + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); + else +#endif + return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); +} +//------------------------------------------------------------------------------ + +inline bool IsHorizontal(TEdge &e) +{ + return e.Dx == HORIZONTAL; +} +//------------------------------------------------------------------------------ + +inline double GetDx(const IntPoint pt1, const IntPoint pt2) +{ + return (pt1.Y == pt2.Y) ? + HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); +} +//--------------------------------------------------------------------------- + +inline void SetDx(TEdge &e) +{ + cInt dy = (e.Top.Y - e.Bot.Y); + if (dy == 0) e.Dx = HORIZONTAL; + else e.Dx = (double)(e.Top.X - e.Bot.X) / dy; +} +//--------------------------------------------------------------------------- + +inline void SwapSides(TEdge &Edge1, TEdge &Edge2) +{ + EdgeSide Side = Edge1.Side; + Edge1.Side = Edge2.Side; + Edge2.Side = Side; +} +//------------------------------------------------------------------------------ + +inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2) +{ + int OutIdx = Edge1.OutIdx; + Edge1.OutIdx = Edge2.OutIdx; + Edge2.OutIdx = OutIdx; +} +//------------------------------------------------------------------------------ + +inline cInt TopX(TEdge &edge, const cInt currentY) +{ + return ( currentY == edge.Top.Y ) ? + edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y)); +} +//------------------------------------------------------------------------------ + +void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip) +{ +#ifdef use_xyz + ip.Z = 0; +#endif + + double b1, b2; + if (Edge1.Dx == Edge2.Dx) + { + ip.Y = Edge1.Curr.Y; + ip.X = TopX(Edge1, ip.Y); + return; + } + else if (Edge1.Dx == 0) + { + ip.X = Edge1.Bot.X; + if (IsHorizontal(Edge2)) + ip.Y = Edge2.Bot.Y; + else + { + b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx); + ip.Y = Round(ip.X / Edge2.Dx + b2); + } + } + else if (Edge2.Dx == 0) + { + ip.X = Edge2.Bot.X; + if (IsHorizontal(Edge1)) + ip.Y = Edge1.Bot.Y; + else + { + b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx); + ip.Y = Round(ip.X / Edge1.Dx + b1); + } + } + else + { + b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx; + b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx; + double q = (b2-b1) / (Edge1.Dx - Edge2.Dx); + ip.Y = Round(q); + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = Round(Edge1.Dx * q + b1); + else + ip.X = Round(Edge2.Dx * q + b2); + } + + if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y) + { + if (Edge1.Top.Y > Edge2.Top.Y) + ip.Y = Edge1.Top.Y; + else + ip.Y = Edge2.Top.Y; + if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) + ip.X = TopX(Edge1, ip.Y); + else + ip.X = TopX(Edge2, ip.Y); + } + //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ... + if (ip.Y > Edge1.Curr.Y) + { + ip.Y = Edge1.Curr.Y; + //use the more vertical edge to derive X ... + if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx)) + ip.X = TopX(Edge2, ip.Y); else + ip.X = TopX(Edge1, ip.Y); + } +} +//------------------------------------------------------------------------------ + +void ReversePolyPtLinks(OutPt *pp) +{ + if (!pp) return; + OutPt *pp1, *pp2; + pp1 = pp; + do { + pp2 = pp1->Next; + pp1->Next = pp1->Prev; + pp1->Prev = pp2; + pp1 = pp2; + } while( pp1 != pp ); +} +//------------------------------------------------------------------------------ + +void DisposeOutPts(OutPt*& pp) +{ + if (pp == 0) return; + pp->Prev->Next = 0; + while( pp ) + { + OutPt *tmpPp = pp; + pp = pp->Next; + delete tmpPp; + } +} +//------------------------------------------------------------------------------ + +inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt) +{ + std::memset(e, 0, sizeof(TEdge)); + e->Next = eNext; + e->Prev = ePrev; + e->Curr = Pt; + e->OutIdx = Unassigned; +} +//------------------------------------------------------------------------------ + +void InitEdge2(TEdge& e, PolyType Pt) +{ + if (e.Curr.Y >= e.Next->Curr.Y) + { + e.Bot = e.Curr; + e.Top = e.Next->Curr; + } else + { + e.Top = e.Curr; + e.Bot = e.Next->Curr; + } + SetDx(e); + e.PolyTyp = Pt; +} +//------------------------------------------------------------------------------ + +TEdge* RemoveEdge(TEdge* e) +{ + //removes e from double_linked_list (but without removing from memory) + e->Prev->Next = e->Next; + e->Next->Prev = e->Prev; + TEdge* result = e->Next; + e->Prev = 0; //flag as removed (see ClipperBase.Clear) + return result; +} +//------------------------------------------------------------------------------ + +inline void ReverseHorizontal(TEdge &e) +{ + //swap horizontal edges' Top and Bottom x's so they follow the natural + //progression of the bounds - ie so their xbots will align with the + //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] + std::swap(e.Top.X, e.Bot.X); +#ifdef use_xyz + std::swap(e.Top.Z, e.Bot.Z); +#endif +} +//------------------------------------------------------------------------------ + +void SwapPoints(IntPoint &pt1, IntPoint &pt2) +{ + IntPoint tmp = pt1; + pt1 = pt2; + pt2 = tmp; +} +//------------------------------------------------------------------------------ + +bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, + IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) +{ + //precondition: segments are Collinear. + if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) + { + if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); + if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); + if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; + return pt1.X < pt2.X; + } else + { + if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); + if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); + if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; + return pt1.Y > pt2.Y; + } +} +//------------------------------------------------------------------------------ + +bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) +{ + OutPt *p = btmPt1->Prev; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev; + double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + p = btmPt1->Next; + while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next; + double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt)); + + p = btmPt2->Prev; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev; + double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + p = btmPt2->Next; + while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next; + double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt)); + + if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) && + std::min(dx1p, dx1n) == std::min(dx2p, dx2n)) + return Area(btmPt1) > 0; //if otherwise identical use orientation + else + return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); +} +//------------------------------------------------------------------------------ + +OutPt* GetBottomPt(OutPt *pp) +{ + OutPt* dups = 0; + OutPt* p = pp->Next; + while (p != pp) + { + if (p->Pt.Y > pp->Pt.Y) + { + pp = p; + dups = 0; + } + else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X) + { + if (p->Pt.X < pp->Pt.X) + { + dups = 0; + pp = p; + } else + { + if (p->Next != pp && p->Prev != pp) dups = p; + } + } + p = p->Next; + } + if (dups) + { + //there appears to be at least 2 vertices at BottomPt so ... + while (dups != p) + { + if (!FirstIsBottomPt(p, dups)) pp = dups; + dups = dups->Next; + while (dups->Pt != pp->Pt) dups = dups->Next; + } + } + return pp; +} +//------------------------------------------------------------------------------ + +bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, + const IntPoint pt2, const IntPoint pt3) +{ + if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2)) + return false; + else if (pt1.X != pt3.X) + return (pt2.X > pt1.X) == (pt2.X < pt3.X); + else + return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y); +} +//------------------------------------------------------------------------------ + +bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) +{ + if (seg1a > seg1b) std::swap(seg1a, seg1b); + if (seg2a > seg2b) std::swap(seg2a, seg2b); + return (seg1a < seg2b) && (seg2a < seg1b); +} + +//------------------------------------------------------------------------------ +// ClipperBase class methods ... +//------------------------------------------------------------------------------ + +ClipperBase::ClipperBase() //constructor +{ + m_CurrentLM = m_MinimaList.begin(); //begin() == end() here + m_UseFullRange = false; +} +//------------------------------------------------------------------------------ + +ClipperBase::~ClipperBase() //destructor +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void RangeTest(const IntPoint& Pt, bool& useFullRange) +{ + if (useFullRange) + { + if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange) + throw clipperException("Coordinate outside allowed range"); + } + else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange) + { + useFullRange = true; + RangeTest(Pt, useFullRange); + } +} +//------------------------------------------------------------------------------ + +TEdge* FindNextLocMin(TEdge* E) +{ + for (;;) + { + while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next; + if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break; + while (IsHorizontal(*E->Prev)) E = E->Prev; + TEdge* E2 = E; + while (IsHorizontal(*E)) E = E->Next; + if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz. + if (E2->Prev->Bot.X < E->Bot.X) E = E2; + break; + } + return E; +} +//------------------------------------------------------------------------------ + +TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward) +{ + TEdge *Result = E; + TEdge *Horz = 0; + + if (E->OutIdx == Skip) + { + //if edges still remain in the current bound beyond the skip edge then + //create another LocMin and call ProcessBound once more + if (NextIsForward) + { + while (E->Top.Y == E->Next->Bot.Y) E = E->Next; + //don't include top horizontals when parsing a bound a second time, + //they will be contained in the opposite bound ... + while (E != Result && IsHorizontal(*E)) E = E->Prev; + } + else + { + while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev; + while (E != Result && IsHorizontal(*E)) E = E->Next; + } + + if (E == Result) + { + if (NextIsForward) Result = E->Next; + else Result = E->Prev; + } + else + { + //there are more edges in the bound beyond result starting with E + if (NextIsForward) + E = Result->Next; + else + E = Result->Prev; + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + locMin.LeftBound = 0; + locMin.RightBound = E; + E->WindDelta = 0; + Result = ProcessBound(E, NextIsForward); + m_MinimaList.push_back(locMin); + } + return Result; + } + + TEdge *EStart; + + if (IsHorizontal(*E)) + { + //We need to be careful with open paths because this may not be a + //true local minima (ie E may be following a skip edge). + //Also, consecutive horz. edges may start heading left before going right. + if (NextIsForward) + EStart = E->Prev; + else + EStart = E->Next; + if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge + { + if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X) + ReverseHorizontal(*E); + } + else if (EStart->Bot.X != E->Bot.X) + ReverseHorizontal(*E); + } + + EStart = E; + if (NextIsForward) + { + while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip) + Result = Result->Next; + if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip) + { + //nb: at the top of a bound, horizontals are added to the bound + //only when the preceding edge attaches to the horizontal's left vertex + //unless a Skip edge is encountered when that becomes the top divide + Horz = Result; + while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev; + if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev; + } + while (E != Result) + { + E->NextInLML = E->Next; + if (IsHorizontal(*E) && E != EStart && + E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + E = E->Next; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X) + ReverseHorizontal(*E); + Result = Result->Next; //move to the edge just beyond current bound + } else + { + while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip) + Result = Result->Prev; + if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip) + { + Horz = Result; + while (IsHorizontal(*Horz->Next)) Horz = Horz->Next; + if (Horz->Next->Top.X == Result->Prev->Top.X || + Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next; + } + + while (E != Result) + { + E->NextInLML = E->Prev; + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + E = E->Prev; + } + if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X) + ReverseHorizontal(*E); + Result = Result->Prev; //move to the edge just beyond current bound + } + + return Result; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) +{ +#ifdef use_lines + if (!Closed && PolyTyp == ptClip) + throw clipperException("AddPath: Open paths must be subject."); +#else + if (!Closed) + throw clipperException("AddPath: Open paths have been disabled."); +#endif + + int highI = (int)pg.size() -1; + if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI; + while (highI > 0 && (pg[highI] == pg[highI -1])) --highI; + if ((Closed && highI < 2) || (!Closed && highI < 1)) return false; + + //create a new edge array ... + TEdge *edges = new TEdge [highI +1]; + + bool IsFlat = true; + //1. Basic (first) edge initialization ... + try + { + edges[1].Curr = pg[1]; + RangeTest(pg[0], m_UseFullRange); + RangeTest(pg[highI], m_UseFullRange); + InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]); + InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]); + for (int i = highI - 1; i >= 1; --i) + { + RangeTest(pg[i], m_UseFullRange); + InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]); + } + } + catch(...) + { + delete [] edges; + throw; //range test fails + } + TEdge *eStart = &edges[0]; + + //2. Remove duplicate vertices, and (when closed) collinear edges ... + TEdge *E = eStart, *eLoopStop = eStart; + for (;;) + { + //nb: allows matching start and end points when not Closed ... + if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart)) + { + if (E == E->Next) break; + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + eLoopStop = E; + continue; + } + if (E->Prev == E->Next) + break; //only two vertices + else if (Closed && + SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) && + (!m_PreserveCollinear || + !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr))) + { + //Collinear edges are allowed for open paths but in closed paths + //the default is to merge adjacent collinear edges into a single edge. + //However, if the PreserveCollinear property is enabled, only overlapping + //collinear edges (ie spikes) will be removed from closed paths. + if (E == eStart) eStart = E->Next; + E = RemoveEdge(E); + E = E->Prev; + eLoopStop = E; + continue; + } + E = E->Next; + if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break; + } + + if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next))) + { + delete [] edges; + return false; + } + + if (!Closed) + { + m_HasOpenPaths = true; + eStart->Prev->OutIdx = Skip; + } + + //3. Do second stage of edge initialization ... + E = eStart; + do + { + InitEdge2(*E, PolyTyp); + E = E->Next; + if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false; + } + while (E != eStart); + + //4. Finally, add edge bounds to LocalMinima list ... + + //Totally flat paths must be handled differently when adding them + //to LocalMinima list to avoid endless loops etc ... + if (IsFlat) + { + if (Closed) + { + delete [] edges; + return false; + } + E->Prev->OutIdx = Skip; + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + locMin.LeftBound = 0; + locMin.RightBound = E; + locMin.RightBound->Side = esRight; + locMin.RightBound->WindDelta = 0; + for (;;) + { + if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); + if (E->Next->OutIdx == Skip) break; + E->NextInLML = E->Next; + E = E->Next; + } + m_MinimaList.push_back(locMin); + m_edges.push_back(edges); + return true; + } + + m_edges.push_back(edges); + bool leftBoundIsForward; + TEdge* EMin = 0; + + //workaround to avoid an endless loop in the while loop below when + //open paths have matching start and end points ... + if (E->Prev->Bot == E->Prev->Top) E = E->Next; + + for (;;) + { + E = FindNextLocMin(E); + if (E == EMin) break; + else if (!EMin) EMin = E; + + //E and E.Prev now share a local minima (left aligned if horizontal). + //Compare their slopes to find which starts which bound ... + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + if (E->Dx < E->Prev->Dx) + { + locMin.LeftBound = E->Prev; + locMin.RightBound = E; + leftBoundIsForward = false; //Q.nextInLML = Q.prev + } else + { + locMin.LeftBound = E; + locMin.RightBound = E->Prev; + leftBoundIsForward = true; //Q.nextInLML = Q.next + } + + if (!Closed) locMin.LeftBound->WindDelta = 0; + else if (locMin.LeftBound->Next == locMin.RightBound) + locMin.LeftBound->WindDelta = -1; + else locMin.LeftBound->WindDelta = 1; + locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta; + + E = ProcessBound(locMin.LeftBound, leftBoundIsForward); + if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); + + TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward); + if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward); + + if (locMin.LeftBound->OutIdx == Skip) + locMin.LeftBound = 0; + else if (locMin.RightBound->OutIdx == Skip) + locMin.RightBound = 0; + m_MinimaList.push_back(locMin); + if (!leftBoundIsForward) E = E2; + } + return true; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed) +{ + bool result = false; + for (Paths::size_type i = 0; i < ppg.size(); ++i) + if (AddPath(ppg[i], PolyTyp, Closed)) result = true; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Clear() +{ + DisposeLocalMinimaList(); + for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) + { + TEdge* edges = m_edges[i]; + delete [] edges; + } + m_edges.clear(); + m_UseFullRange = false; + m_HasOpenPaths = false; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Reset() +{ + m_CurrentLM = m_MinimaList.begin(); + if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process + std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter()); + + m_Scanbeam = ScanbeamList(); //clears/resets priority_queue + //reset all edges ... + for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm) + { + InsertScanbeam(lm->Y); + TEdge* e = lm->LeftBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esLeft; + e->OutIdx = Unassigned; + } + + e = lm->RightBound; + if (e) + { + e->Curr = e->Bot; + e->Side = esRight; + e->OutIdx = Unassigned; + } + } + m_ActiveEdges = 0; + m_CurrentLM = m_MinimaList.begin(); +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeLocalMinimaList() +{ + m_MinimaList.clear(); + m_CurrentLM = m_MinimaList.begin(); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin) +{ + if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false; + locMin = &(*m_CurrentLM); + ++m_CurrentLM; + return true; +} +//------------------------------------------------------------------------------ + +IntRect ClipperBase::GetBounds() +{ + IntRect result; + MinimaList::iterator lm = m_MinimaList.begin(); + if (lm == m_MinimaList.end()) + { + result.left = result.top = result.right = result.bottom = 0; + return result; + } + result.left = lm->LeftBound->Bot.X; + result.top = lm->LeftBound->Bot.Y; + result.right = lm->LeftBound->Bot.X; + result.bottom = lm->LeftBound->Bot.Y; + while (lm != m_MinimaList.end()) + { + //todo - needs fixing for open paths + result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y); + TEdge* e = lm->LeftBound; + for (;;) { + TEdge* bottomE = e; + while (e->NextInLML) + { + if (e->Bot.X < result.left) result.left = e->Bot.X; + if (e->Bot.X > result.right) result.right = e->Bot.X; + e = e->NextInLML; + } + result.left = std::min(result.left, e->Bot.X); + result.right = std::max(result.right, e->Bot.X); + result.left = std::min(result.left, e->Top.X); + result.right = std::max(result.right, e->Top.X); + result.top = std::min(result.top, e->Top.Y); + if (bottomE == lm->LeftBound) e = lm->RightBound; + else break; + } + ++lm; + } + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::InsertScanbeam(const cInt Y) +{ + m_Scanbeam.push(Y); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::PopScanbeam(cInt &Y) +{ + if (m_Scanbeam.empty()) return false; + Y = m_Scanbeam.top(); + m_Scanbeam.pop(); + while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates. + return true; +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeAllOutRecs(){ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + DisposeOutRec(i); + m_PolyOuts.clear(); +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeOutRec(PolyOutList::size_type index) +{ + OutRec *outRec = m_PolyOuts[index]; + if (outRec->Pts) DisposeOutPts(outRec->Pts); + delete outRec; + m_PolyOuts[index] = 0; +} +//------------------------------------------------------------------------------ + +void ClipperBase::DeleteFromAEL(TEdge *e) +{ + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted + if (AelPrev) AelPrev->NextInAEL = AelNext; + else m_ActiveEdges = AelNext; + if (AelNext) AelNext->PrevInAEL = AelPrev; + e->NextInAEL = 0; + e->PrevInAEL = 0; +} +//------------------------------------------------------------------------------ + +OutRec* ClipperBase::CreateOutRec() +{ + OutRec* result = new OutRec; + result->IsHole = false; + result->IsOpen = false; + result->FirstLeft = 0; + result->Pts = 0; + result->BottomPt = 0; + result->PolyNd = 0; + m_PolyOuts.push_back(result); + result->Idx = (int)m_PolyOuts.size() - 1; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2) +{ + //check that one or other edge hasn't already been removed from AEL ... + if (Edge1->NextInAEL == Edge1->PrevInAEL || + Edge2->NextInAEL == Edge2->PrevInAEL) return; + + if (Edge1->NextInAEL == Edge2) + { + TEdge* Next = Edge2->NextInAEL; + if (Next) Next->PrevInAEL = Edge1; + TEdge* Prev = Edge1->PrevInAEL; + if (Prev) Prev->NextInAEL = Edge2; + Edge2->PrevInAEL = Prev; + Edge2->NextInAEL = Edge1; + Edge1->PrevInAEL = Edge2; + Edge1->NextInAEL = Next; + } + else if (Edge2->NextInAEL == Edge1) + { + TEdge* Next = Edge1->NextInAEL; + if (Next) Next->PrevInAEL = Edge2; + TEdge* Prev = Edge2->PrevInAEL; + if (Prev) Prev->NextInAEL = Edge1; + Edge1->PrevInAEL = Prev; + Edge1->NextInAEL = Edge2; + Edge2->PrevInAEL = Edge1; + Edge2->NextInAEL = Next; + } + else + { + TEdge* Next = Edge1->NextInAEL; + TEdge* Prev = Edge1->PrevInAEL; + Edge1->NextInAEL = Edge2->NextInAEL; + if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1; + Edge1->PrevInAEL = Edge2->PrevInAEL; + if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1; + Edge2->NextInAEL = Next; + if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2; + Edge2->PrevInAEL = Prev; + if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2; + } + + if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1; + else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2; +} +//------------------------------------------------------------------------------ + +void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e) +{ + if (!e->NextInLML) + throw clipperException("UpdateEdgeIntoAEL: invalid call"); + + e->NextInLML->OutIdx = e->OutIdx; + TEdge* AelPrev = e->PrevInAEL; + TEdge* AelNext = e->NextInAEL; + if (AelPrev) AelPrev->NextInAEL = e->NextInLML; + else m_ActiveEdges = e->NextInLML; + if (AelNext) AelNext->PrevInAEL = e->NextInLML; + e->NextInLML->Side = e->Side; + e->NextInLML->WindDelta = e->WindDelta; + e->NextInLML->WindCnt = e->WindCnt; + e->NextInLML->WindCnt2 = e->WindCnt2; + e = e->NextInLML; + e->Curr = e->Bot; + e->PrevInAEL = AelPrev; + e->NextInAEL = AelNext; + if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::LocalMinimaPending() +{ + return (m_CurrentLM != m_MinimaList.end()); +} + +//------------------------------------------------------------------------------ +// TClipper methods ... +//------------------------------------------------------------------------------ + +Clipper::Clipper(int initOptions) : ClipperBase() //constructor +{ + m_ExecuteLocked = false; + m_UseFullRange = false; + m_ReverseOutput = ((initOptions & ioReverseSolution) != 0); + m_StrictSimple = ((initOptions & ioStrictlySimple) != 0); + m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0); + m_HasOpenPaths = false; +#ifdef use_xyz + m_ZFill = 0; +#endif +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz +void Clipper::ZFillFunction(ZFillCallback zFillFunc) +{ + m_ZFill = zFillFunc; +} +//------------------------------------------------------------------------------ +#endif + +bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType) +{ + return Execute(clipType, solution, fillType, fillType); +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType) +{ + return Execute(clipType, polytree, fillType, fillType); +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, Paths &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + if (m_HasOpenPaths) + throw clipperException("Error: PolyTree struct is needed for open path clipping."); + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = false; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult(solution); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree& polytree, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = true; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult2(polytree); + DisposeAllOutRecs(); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::FixHoleLinkage(OutRec &outrec) +{ + //skip OutRecs that (a) contain outermost polygons or + //(b) already have the correct owner/child linkage ... + if (!outrec.FirstLeft || + (outrec.IsHole != outrec.FirstLeft->IsHole && + outrec.FirstLeft->Pts)) return; + + OutRec* orfl = outrec.FirstLeft; + while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts)) + orfl = orfl->FirstLeft; + outrec.FirstLeft = orfl; +} +//------------------------------------------------------------------------------ + +bool Clipper::ExecuteInternal() +{ + bool succeeded = true; + try { + Reset(); + m_Maxima = MaximaList(); + m_SortedEdges = 0; + + succeeded = true; + cInt botY, topY; + if (!PopScanbeam(botY)) return false; + InsertLocalMinimaIntoAEL(botY); + while (PopScanbeam(topY) || LocalMinimaPending()) + { + ProcessHorizontals(); + ClearGhostJoins(); + if (!ProcessIntersections(topY)) + { + succeeded = false; + break; + } + ProcessEdgesAtTopOfScanbeam(topY); + botY = topY; + InsertLocalMinimaIntoAEL(botY); + } + } + catch(...) + { + succeeded = false; + } + + if (succeeded) + { + //fix orientations ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->Pts || outRec->IsOpen) continue; + if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0)) + ReversePolyPtLinks(outRec->Pts); + } + + if (!m_Joins.empty()) JoinCommonEdges(); + + //unfortunately FixupOutPolygon() must be done after JoinCommonEdges() + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->Pts) continue; + if (outRec->IsOpen) + FixupOutPolyline(*outRec); + else + FixupOutPolygon(*outRec); + } + + if (m_StrictSimple) DoSimplePolygons(); + } + + ClearJoins(); + ClearGhostJoins(); + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::SetWindingCount(TEdge &edge) +{ + TEdge *e = edge.PrevInAEL; + //find the edge of the same polytype that immediately preceeds 'edge' in AEL + while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL; + if (!e) + { + if (edge.WindDelta == 0) + { + PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType); + edge.WindCnt = (pft == pftNegative ? -1 : 1); + } + else + edge.WindCnt = edge.WindDelta; + edge.WindCnt2 = 0; + e = m_ActiveEdges; //ie get ready to calc WindCnt2 + } + else if (edge.WindDelta == 0 && m_ClipType != ctUnion) + { + edge.WindCnt = 1; + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else if (IsEvenOddFillType(edge)) + { + //EvenOdd filling ... + if (edge.WindDelta == 0) + { + //are we inside a subj polygon ... + bool Inside = true; + TEdge *e2 = e->PrevInAEL; + while (e2) + { + if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0) + Inside = !Inside; + e2 = e2->PrevInAEL; + } + edge.WindCnt = (Inside ? 0 : 1); + } + else + { + edge.WindCnt = edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + else + { + //nonZero, Positive or Negative filling ... + if (e->WindCnt * e->WindDelta < 0) + { + //prev edge is 'decreasing' WindCount (WC) toward zero + //so we're outside the previous polygon ... + if (Abs(e->WindCnt) > 1) + { + //outside prev poly but still inside another. + //when reversing direction of prev poly use the same WC + if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise continue to 'decrease' WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + else + //now outside all polys of same polytype so set own WC ... + edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta); + } else + { + //prev edge is 'increasing' WindCount (WC) away from zero + //so we're inside the previous polygon ... + if (edge.WindDelta == 0) + edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1); + //if wind direction is reversing prev then use same WC + else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt; + //otherwise add to WC ... + else edge.WindCnt = e->WindCnt + edge.WindDelta; + } + edge.WindCnt2 = e->WindCnt2; + e = e->NextInAEL; //ie get ready to calc WindCnt2 + } + + //update WindCnt2 ... + if (IsEvenOddAltFillType(edge)) + { + //EvenOdd filling ... + while (e != &edge) + { + if (e->WindDelta != 0) + edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0); + e = e->NextInAEL; + } + } else + { + //nonZero, Positive or Negative filling ... + while ( e != &edge ) + { + edge.WindCnt2 += e->WindDelta; + e = e->NextInAEL; + } + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_SubjFillType == pftEvenOdd; else + return m_ClipFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const +{ + if (edge.PolyTyp == ptSubject) + return m_ClipFillType == pftEvenOdd; else + return m_SubjFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsContributing(const TEdge& edge) const +{ + PolyFillType pft, pft2; + if (edge.PolyTyp == ptSubject) + { + pft = m_SubjFillType; + pft2 = m_ClipFillType; + } else + { + pft = m_ClipFillType; + pft2 = m_SubjFillType; + } + + switch(pft) + { + case pftEvenOdd: + //return false if a subj line has been flagged as inside a subj polygon + if (edge.WindDelta == 0 && edge.WindCnt != 1) return false; + break; + case pftNonZero: + if (Abs(edge.WindCnt) != 1) return false; + break; + case pftPositive: + if (edge.WindCnt != 1) return false; + break; + default: //pftNegative + if (edge.WindCnt != -1) return false; + } + + switch(m_ClipType) + { + case ctIntersection: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctUnion: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + break; + case ctDifference: + if (edge.PolyTyp == ptSubject) + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 != 0); + case pftPositive: + return (edge.WindCnt2 > 0); + default: + return (edge.WindCnt2 < 0); + } + break; + case ctXor: + if (edge.WindDelta == 0) //XOr always contributing unless open + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.WindCnt2 == 0); + case pftPositive: + return (edge.WindCnt2 <= 0); + default: + return (edge.WindCnt2 >= 0); + } + else + return true; + break; + default: + return true; + } +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + OutPt* result; + TEdge *e, *prevE; + if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx )) + { + result = AddOutPt(e1, Pt); + e2->OutIdx = e1->OutIdx; + e1->Side = esLeft; + e2->Side = esRight; + e = e1; + if (e->PrevInAEL == e2) + prevE = e2->PrevInAEL; + else + prevE = e->PrevInAEL; + } else + { + result = AddOutPt(e2, Pt); + e1->OutIdx = e2->OutIdx; + e1->Side = esRight; + e2->Side = esLeft; + e = e2; + if (e->PrevInAEL == e1) + prevE = e1->PrevInAEL; + else + prevE = e->PrevInAEL; + } + + if (prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y) + { + cInt xPrev = TopX(*prevE, Pt.Y); + cInt xE = TopX(*e, Pt.Y); + if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) && + SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange)) + { + OutPt* outPt = AddOutPt(prevE, Pt); + AddJoin(result, outPt, e->Top); + } + } + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt) +{ + AddOutPt( e1, Pt ); + if (e2->WindDelta == 0) AddOutPt(e2, Pt); + if( e1->OutIdx == e2->OutIdx ) + { + e1->OutIdx = Unassigned; + e2->OutIdx = Unassigned; + } + else if (e1->OutIdx < e2->OutIdx) + AppendPolygon(e1, e2); + else + AppendPolygon(e2, e1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddEdgeToSEL(TEdge *edge) +{ + //SEL pointers in PEdge are reused to build a list of horizontal edges. + //However, we don't need to worry about order with horizontal edge processing. + if( !m_SortedEdges ) + { + m_SortedEdges = edge; + edge->PrevInSEL = 0; + edge->NextInSEL = 0; + } + else + { + edge->NextInSEL = m_SortedEdges; + edge->PrevInSEL = 0; + m_SortedEdges->PrevInSEL = edge; + m_SortedEdges = edge; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::PopEdgeFromSEL(TEdge *&edge) +{ + if (!m_SortedEdges) return false; + edge = m_SortedEdges; + DeleteFromSEL(m_SortedEdges); + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::CopyAELToSEL() +{ + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while ( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op1; + j->OutPt2 = op2; + j->OffPt = OffPt; + m_Joins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearJoins() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + delete m_Joins[i]; + m_Joins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearGhostJoins() +{ + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++) + delete m_GhostJoins[i]; + m_GhostJoins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) +{ + Join* j = new Join; + j->OutPt1 = op; + j->OutPt2 = 0; + j->OffPt = OffPt; + m_GhostJoins.push_back(j); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) +{ + const LocalMinimum *lm; + while (PopLocalMinima(botY, lm)) + { + TEdge* lb = lm->LeftBound; + TEdge* rb = lm->RightBound; + + OutPt *Op1 = 0; + if (!lb) + { + //nb: don't insert LB into either AEL or SEL + InsertEdgeIntoAEL(rb, 0); + SetWindingCount(*rb); + if (IsContributing(*rb)) + Op1 = AddOutPt(rb, rb->Bot); + } + else if (!rb) + { + InsertEdgeIntoAEL(lb, 0); + SetWindingCount(*lb); + if (IsContributing(*lb)) + Op1 = AddOutPt(lb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + else + { + InsertEdgeIntoAEL(lb, 0); + InsertEdgeIntoAEL(rb, lb); + SetWindingCount( *lb ); + rb->WindCnt = lb->WindCnt; + rb->WindCnt2 = lb->WindCnt2; + if (IsContributing(*lb)) + Op1 = AddLocalMinPoly(lb, rb, lb->Bot); + InsertScanbeam(lb->Top.Y); + } + + if (rb) + { + if (IsHorizontal(*rb)) + { + AddEdgeToSEL(rb); + if (rb->NextInLML) + InsertScanbeam(rb->NextInLML->Top.Y); + } + else InsertScanbeam( rb->Top.Y ); + } + + if (!lb || !rb) continue; + + //if any output polygons share an edge, they'll need joining later ... + if (Op1 && IsHorizontal(*rb) && + m_GhostJoins.size() > 0 && (rb->WindDelta != 0)) + { + for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i) + { + Join* jr = m_GhostJoins[i]; + //if the horizontal Rb and a 'ghost' horizontal overlap, then convert + //the 'ghost' join to a real join ready for later ... + if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X)) + AddJoin(jr->OutPt1, Op1, jr->OffPt); + } + } + + if (lb->OutIdx >= 0 && lb->PrevInAEL && + lb->PrevInAEL->Curr.X == lb->Bot.X && + lb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) && + (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot); + AddJoin(Op1, Op2, lb->Top); + } + + if(lb->NextInAEL != rb) + { + + if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 && + SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) && + (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0)) + { + OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot); + AddJoin(Op1, Op2, rb->Top); + } + + TEdge* e = lb->NextInAEL; + if (e) + { + while( e != rb ) + { + //nb: For calculating winding counts etc, IntersectEdges() assumes + //that param1 will be to the Right of param2 ABOVE the intersection ... + IntersectEdges(rb , e , lb->Curr); //order important here + e = e->NextInAEL; + } + } + } + + } +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromSEL(TEdge *e) +{ + TEdge* SelPrev = e->PrevInSEL; + TEdge* SelNext = e->NextInSEL; + if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted + if( SelPrev ) SelPrev->NextInSEL = SelNext; + else m_SortedEdges = SelNext; + if( SelNext ) SelNext->PrevInSEL = SelPrev; + e->NextInSEL = 0; + e->PrevInSEL = 0; +} +//------------------------------------------------------------------------------ + +#ifdef use_xyz +void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2) +{ + if (pt.Z != 0 || !m_ZFill) return; + else if (pt == e1.Bot) pt.Z = e1.Bot.Z; + else if (pt == e1.Top) pt.Z = e1.Top.Z; + else if (pt == e2.Bot) pt.Z = e2.Bot.Z; + else if (pt == e2.Top) pt.Z = e2.Top.Z; + else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt); +} +//------------------------------------------------------------------------------ +#endif + +void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt) +{ + bool e1Contributing = ( e1->OutIdx >= 0 ); + bool e2Contributing = ( e2->OutIdx >= 0 ); + +#ifdef use_xyz + SetZ(Pt, *e1, *e2); +#endif + +#ifdef use_lines + //if either edge is on an OPEN path ... + if (e1->WindDelta == 0 || e2->WindDelta == 0) + { + //ignore subject-subject open path intersections UNLESS they + //are both open paths, AND they are both 'contributing maximas' ... + if (e1->WindDelta == 0 && e2->WindDelta == 0) return; + + //if intersecting a subj line with a subj poly ... + else if (e1->PolyTyp == e2->PolyTyp && + e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion) + { + if (e1->WindDelta == 0) + { + if (e2Contributing) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + } + else + { + if (e1Contributing) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + } + else if (e1->PolyTyp != e2->PolyTyp) + { + //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ... + if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 && + (m_ClipType != ctUnion || e2->WindCnt2 == 0)) + { + AddOutPt(e1, Pt); + if (e1Contributing) e1->OutIdx = Unassigned; + } + else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) && + (m_ClipType != ctUnion || e1->WindCnt2 == 0)) + { + AddOutPt(e2, Pt); + if (e2Contributing) e2->OutIdx = Unassigned; + } + } + return; + } +#endif + + //update winding counts... + //assumes that e1 will be to the Right of e2 ABOVE the intersection + if ( e1->PolyTyp == e2->PolyTyp ) + { + if ( IsEvenOddFillType( *e1) ) + { + int oldE1WindCnt = e1->WindCnt; + e1->WindCnt = e2->WindCnt; + e2->WindCnt = oldE1WindCnt; + } else + { + if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt; + else e1->WindCnt += e2->WindDelta; + if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt; + else e2->WindCnt -= e1->WindDelta; + } + } else + { + if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta; + else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0; + if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta; + else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0; + } + + PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; + if (e1->PolyTyp == ptSubject) + { + e1FillType = m_SubjFillType; + e1FillType2 = m_ClipFillType; + } else + { + e1FillType = m_ClipFillType; + e1FillType2 = m_SubjFillType; + } + if (e2->PolyTyp == ptSubject) + { + e2FillType = m_SubjFillType; + e2FillType2 = m_ClipFillType; + } else + { + e2FillType = m_ClipFillType; + e2FillType2 = m_SubjFillType; + } + + cInt e1Wc, e2Wc; + switch (e1FillType) + { + case pftPositive: e1Wc = e1->WindCnt; break; + case pftNegative: e1Wc = -e1->WindCnt; break; + default: e1Wc = Abs(e1->WindCnt); + } + switch(e2FillType) + { + case pftPositive: e2Wc = e2->WindCnt; break; + case pftNegative: e2Wc = -e2->WindCnt; break; + default: e2Wc = Abs(e2->WindCnt); + } + + if ( e1Contributing && e2Contributing ) + { + if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || + (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) ) + { + AddLocalMaxPoly(e1, e2, Pt); + } + else + { + AddOutPt(e1, Pt); + AddOutPt(e2, Pt); + SwapSides( *e1 , *e2 ); + SwapPolyIndexes( *e1 , *e2 ); + } + } + else if ( e1Contributing ) + { + if (e2Wc == 0 || e2Wc == 1) + { + AddOutPt(e1, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( e2Contributing ) + { + if (e1Wc == 0 || e1Wc == 1) + { + AddOutPt(e2, Pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1)) + { + //neither edge is currently contributing ... + + cInt e1Wc2, e2Wc2; + switch (e1FillType2) + { + case pftPositive: e1Wc2 = e1->WindCnt2; break; + case pftNegative : e1Wc2 = -e1->WindCnt2; break; + default: e1Wc2 = Abs(e1->WindCnt2); + } + switch (e2FillType2) + { + case pftPositive: e2Wc2 = e2->WindCnt2; break; + case pftNegative: e2Wc2 = -e2->WindCnt2; break; + default: e2Wc2 = Abs(e2->WindCnt2); + } + + if (e1->PolyTyp != e2->PolyTyp) + { + AddLocalMinPoly(e1, e2, Pt); + } + else if (e1Wc == 1 && e2Wc == 1) + switch( m_ClipType ) { + case ctIntersection: + if (e1Wc2 > 0 && e2Wc2 > 0) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctUnion: + if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctDifference: + if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + AddLocalMinPoly(e1, e2, Pt); + break; + case ctXor: + AddLocalMinPoly(e1, e2, Pt); + } + else + SwapSides( *e1, *e2 ); + } +} +//------------------------------------------------------------------------------ + +void Clipper::SetHoleState(TEdge *e, OutRec *outrec) +{ + TEdge *e2 = e->PrevInAEL; + TEdge *eTmp = 0; + while (e2) + { + if (e2->OutIdx >= 0 && e2->WindDelta != 0) + { + if (!eTmp) eTmp = e2; + else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0; + } + e2 = e2->PrevInAEL; + } + if (!eTmp) + { + outrec->FirstLeft = 0; + outrec->IsHole = false; + } + else + { + outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx]; + outrec->IsHole = !outrec->FirstLeft->IsHole; + } +} +//------------------------------------------------------------------------------ + +OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) +{ + //work out which polygon fragment has the correct hole state ... + if (!outRec1->BottomPt) + outRec1->BottomPt = GetBottomPt(outRec1->Pts); + if (!outRec2->BottomPt) + outRec2->BottomPt = GetBottomPt(outRec2->Pts); + OutPt *OutPt1 = outRec1->BottomPt; + OutPt *OutPt2 = outRec2->BottomPt; + if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1; + else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2; + else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1; + else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2; + else if (OutPt1->Next == OutPt1) return outRec2; + else if (OutPt2->Next == OutPt2) return outRec1; + else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1; + else return outRec2; +} +//------------------------------------------------------------------------------ + +bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2) +{ + do + { + outRec1 = outRec1->FirstLeft; + if (outRec1 == outRec2) return true; + } while (outRec1); + return false; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::GetOutRec(int Idx) +{ + OutRec* outrec = m_PolyOuts[Idx]; + while (outrec != m_PolyOuts[outrec->Idx]) + outrec = m_PolyOuts[outrec->Idx]; + return outrec; +} +//------------------------------------------------------------------------------ + +void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) +{ + //get the start and ends of both output polygons ... + OutRec *outRec1 = m_PolyOuts[e1->OutIdx]; + OutRec *outRec2 = m_PolyOuts[e2->OutIdx]; + + OutRec *holeStateRec; + if (OutRec1RightOfOutRec2(outRec1, outRec2)) + holeStateRec = outRec2; + else if (OutRec1RightOfOutRec2(outRec2, outRec1)) + holeStateRec = outRec1; + else + holeStateRec = GetLowermostRec(outRec1, outRec2); + + //get the start and ends of both output polygons and + //join e2 poly onto e1 poly and delete pointers to e2 ... + + OutPt* p1_lft = outRec1->Pts; + OutPt* p1_rt = p1_lft->Prev; + OutPt* p2_lft = outRec2->Pts; + OutPt* p2_rt = p2_lft->Prev; + + //join e2 poly onto e1 poly and delete pointers to e2 ... + if( e1->Side == esLeft ) + { + if( e2->Side == esLeft ) + { + //z y x a b c + ReversePolyPtLinks(p2_lft); + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + outRec1->Pts = p2_rt; + } else + { + //x y z a b c + p2_rt->Next = p1_lft; + p1_lft->Prev = p2_rt; + p2_lft->Prev = p1_rt; + p1_rt->Next = p2_lft; + outRec1->Pts = p2_lft; + } + } else + { + if( e2->Side == esRight ) + { + //a b c z y x + ReversePolyPtLinks(p2_lft); + p1_rt->Next = p2_rt; + p2_rt->Prev = p1_rt; + p2_lft->Next = p1_lft; + p1_lft->Prev = p2_lft; + } else + { + //a b c x y z + p1_rt->Next = p2_lft; + p2_lft->Prev = p1_rt; + p1_lft->Prev = p2_rt; + p2_rt->Next = p1_lft; + } + } + + outRec1->BottomPt = 0; + if (holeStateRec == outRec2) + { + if (outRec2->FirstLeft != outRec1) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec1->IsHole = outRec2->IsHole; + } + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->FirstLeft = outRec1; + + int OKIdx = e1->OutIdx; + int ObsoleteIdx = e2->OutIdx; + + e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly + e2->OutIdx = Unassigned; + + TEdge* e = m_ActiveEdges; + while( e ) + { + if( e->OutIdx == ObsoleteIdx ) + { + e->OutIdx = OKIdx; + e->Side = e1->Side; + break; + } + e = e->NextInAEL; + } + + outRec2->Idx = outRec1->Idx; +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt) +{ + if( e->OutIdx < 0 ) + { + OutRec *outRec = CreateOutRec(); + outRec->IsOpen = (e->WindDelta == 0); + OutPt* newOp = new OutPt; + outRec->Pts = newOp; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = newOp; + newOp->Prev = newOp; + if (!outRec->IsOpen) + SetHoleState(e, outRec); + e->OutIdx = outRec->Idx; + return newOp; + } else + { + OutRec *outRec = m_PolyOuts[e->OutIdx]; + //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most' + OutPt* op = outRec->Pts; + + bool ToFront = (e->Side == esLeft); + if (ToFront && (pt == op->Pt)) return op; + else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev; + + OutPt* newOp = new OutPt; + newOp->Idx = outRec->Idx; + newOp->Pt = pt; + newOp->Next = op; + newOp->Prev = op->Prev; + newOp->Prev->Next = newOp; + op->Prev = newOp; + if (ToFront) outRec->Pts = newOp; + return newOp; + } +} +//------------------------------------------------------------------------------ + +OutPt* Clipper::GetLastOutPt(TEdge *e) +{ + OutRec *outRec = m_PolyOuts[e->OutIdx]; + if (e->Side == esLeft) + return outRec->Pts; + else + return outRec->Pts->Prev; +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontals() +{ + TEdge* horzEdge; + while (PopEdgeFromSEL(horzEdge)) + ProcessHorizontal(horzEdge); +} +//------------------------------------------------------------------------------ + +inline bool IsMinima(TEdge *e) +{ + return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e); +} +//------------------------------------------------------------------------------ + +inline bool IsMaxima(TEdge *e, const cInt Y) +{ + return e && e->Top.Y == Y && !e->NextInLML; +} +//------------------------------------------------------------------------------ + +inline bool IsIntermediate(TEdge *e, const cInt Y) +{ + return e->Top.Y == Y && e->NextInLML; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPair(TEdge *e) +{ + if ((e->Next->Top == e->Top) && !e->Next->NextInLML) + return e->Next; + else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML) + return e->Prev; + else return 0; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPairEx(TEdge *e) +{ + //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal) + TEdge* result = GetMaximaPair(e); + if (result && (result->OutIdx == Skip || + (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0; + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2) +{ + if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) ) return; + if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) ) return; + + if( Edge1->NextInSEL == Edge2 ) + { + TEdge* Next = Edge2->NextInSEL; + if( Next ) Next->PrevInSEL = Edge1; + TEdge* Prev = Edge1->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge2; + Edge2->PrevInSEL = Prev; + Edge2->NextInSEL = Edge1; + Edge1->PrevInSEL = Edge2; + Edge1->NextInSEL = Next; + } + else if( Edge2->NextInSEL == Edge1 ) + { + TEdge* Next = Edge1->NextInSEL; + if( Next ) Next->PrevInSEL = Edge2; + TEdge* Prev = Edge2->PrevInSEL; + if( Prev ) Prev->NextInSEL = Edge1; + Edge1->PrevInSEL = Prev; + Edge1->NextInSEL = Edge2; + Edge2->PrevInSEL = Edge1; + Edge2->NextInSEL = Next; + } + else + { + TEdge* Next = Edge1->NextInSEL; + TEdge* Prev = Edge1->PrevInSEL; + Edge1->NextInSEL = Edge2->NextInSEL; + if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1; + Edge1->PrevInSEL = Edge2->PrevInSEL; + if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1; + Edge2->NextInSEL = Next; + if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2; + Edge2->PrevInSEL = Prev; + if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2; + } + + if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1; + else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2; +} +//------------------------------------------------------------------------------ + +TEdge* GetNextInAEL(TEdge *e, Direction dir) +{ + return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL; +} +//------------------------------------------------------------------------------ + +void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right) +{ + if (HorzEdge.Bot.X < HorzEdge.Top.X) + { + Left = HorzEdge.Bot.X; + Right = HorzEdge.Top.X; + Dir = dLeftToRight; + } else + { + Left = HorzEdge.Top.X; + Right = HorzEdge.Bot.X; + Dir = dRightToLeft; + } +} +//------------------------------------------------------------------------ + +/******************************************************************************* +* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or * +* Bottom of a scanbeam) are processed as if layered. The order in which HEs * +* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#] * +* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs), * +* and with other non-horizontal edges [*]. Once these intersections are * +* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into * +* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. * +*******************************************************************************/ + +void Clipper::ProcessHorizontal(TEdge *horzEdge) +{ + Direction dir; + cInt horzLeft, horzRight; + bool IsOpen = (horzEdge->WindDelta == 0); + + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + + TEdge* eLastHorz = horzEdge, *eMaxPair = 0; + while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML)) + eLastHorz = eLastHorz->NextInLML; + if (!eLastHorz->NextInLML) + eMaxPair = GetMaximaPair(eLastHorz); + + MaximaList::const_iterator maxIt; + MaximaList::const_reverse_iterator maxRit; + if (m_Maxima.size() > 0) + { + //get the first maxima in range (X) ... + if (dir == dLeftToRight) + { + maxIt = m_Maxima.begin(); + while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++; + if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X) + maxIt = m_Maxima.end(); + } + else + { + maxRit = m_Maxima.rbegin(); + while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++; + if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X) + maxRit = m_Maxima.rend(); + } + } + + OutPt* op1 = 0; + + for (;;) //loop through consec. horizontal edges + { + + bool IsLastHorz = (horzEdge == eLastHorz); + TEdge* e = GetNextInAEL(horzEdge, dir); + while(e) + { + + //this code block inserts extra coords into horizontal edges (in output + //polygons) whereever maxima touch these horizontal edges. This helps + //'simplifying' polygons (ie if the Simplify property is set). + if (m_Maxima.size() > 0) + { + if (dir == dLeftToRight) + { + while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X) + { + if (horzEdge->OutIdx >= 0 && !IsOpen) + AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y)); + maxIt++; + } + } + else + { + while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X) + { + if (horzEdge->OutIdx >= 0 && !IsOpen) + AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y)); + maxRit++; + } + } + }; + + if ((dir == dLeftToRight && e->Curr.X > horzRight) || + (dir == dRightToLeft && e->Curr.X < horzLeft)) break; + + //Also break if we've got to the end of an intermediate horizontal edge ... + //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal. + if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML && + e->Dx < horzEdge->NextInLML->Dx) break; + + if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times + { +#ifdef use_xyz + if (dir == dLeftToRight) SetZ(e->Curr, *horzEdge, *e); + else SetZ(e->Curr, *e, *horzEdge); +#endif + op1 = AddOutPt(horzEdge, e->Curr); + TEdge* eNextHorz = m_SortedEdges; + while (eNextHorz) + { + if (eNextHorz->OutIdx >= 0 && + HorzSegmentsOverlap(horzEdge->Bot.X, + horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) + { + OutPt* op2 = GetLastOutPt(eNextHorz); + AddJoin(op2, op1, eNextHorz->Top); + } + eNextHorz = eNextHorz->NextInSEL; + } + AddGhostJoin(op1, horzEdge->Bot); + } + + //OK, so far we're still in range of the horizontal Edge but make sure + //we're at the last of consec. horizontals when matching with eMaxPair + if(e == eMaxPair && IsLastHorz) + { + if (horzEdge->OutIdx >= 0) + AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top); + DeleteFromAEL(horzEdge); + DeleteFromAEL(eMaxPair); + return; + } + + if(dir == dLeftToRight) + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges(horzEdge, e, Pt); + } + else + { + IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y); + IntersectEdges( e, horzEdge, Pt); + } + TEdge* eNext = GetNextInAEL(e, dir); + SwapPositionsInAEL( horzEdge, e ); + e = eNext; + } //end while(e) + + //Break out of loop if HorzEdge.NextInLML is not also horizontal ... + if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break; + + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot); + GetHorzDirection(*horzEdge, dir, horzLeft, horzRight); + + } //end for (;;) + + if (horzEdge->OutIdx >= 0 && !op1) + { + op1 = GetLastOutPt(horzEdge); + TEdge* eNextHorz = m_SortedEdges; + while (eNextHorz) + { + if (eNextHorz->OutIdx >= 0 && + HorzSegmentsOverlap(horzEdge->Bot.X, + horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X)) + { + OutPt* op2 = GetLastOutPt(eNextHorz); + AddJoin(op2, op1, eNextHorz->Top); + } + eNextHorz = eNextHorz->NextInSEL; + } + AddGhostJoin(op1, horzEdge->Top); + } + + if (horzEdge->NextInLML) + { + if(horzEdge->OutIdx >= 0) + { + op1 = AddOutPt( horzEdge, horzEdge->Top); + UpdateEdgeIntoAEL(horzEdge); + if (horzEdge->WindDelta == 0) return; + //nb: HorzEdge is no longer horizontal here + TEdge* ePrev = horzEdge->PrevInAEL; + TEdge* eNext = horzEdge->NextInAEL; + if (ePrev && ePrev->Curr.X == horzEdge->Bot.X && + ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 && + (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(*horzEdge, *ePrev, m_UseFullRange))) + { + OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + else if (eNext && eNext->Curr.X == horzEdge->Bot.X && + eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(*horzEdge, *eNext, m_UseFullRange)) + { + OutPt* op2 = AddOutPt(eNext, horzEdge->Bot); + AddJoin(op1, op2, horzEdge->Top); + } + } + else + UpdateEdgeIntoAEL(horzEdge); + } + else + { + if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top); + DeleteFromAEL(horzEdge); + } +} +//------------------------------------------------------------------------------ + +bool Clipper::ProcessIntersections(const cInt topY) +{ + if( !m_ActiveEdges ) return true; + try { + BuildIntersectList(topY); + size_t IlSize = m_IntersectList.size(); + if (IlSize == 0) return true; + if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList(); + else return false; + } + catch(...) + { + m_SortedEdges = 0; + DisposeIntersectNodes(); + throw clipperException("ProcessIntersections error"); + } + m_SortedEdges = 0; + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeIntersectNodes() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i ) + delete m_IntersectList[i]; + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::BuildIntersectList(const cInt topY) +{ + if ( !m_ActiveEdges ) return; + + //prepare for sorting ... + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while( e ) + { + e->PrevInSEL = e->PrevInAEL; + e->NextInSEL = e->NextInAEL; + e->Curr.X = TopX( *e, topY ); + e = e->NextInAEL; + } + + //bubblesort ... + bool isModified; + do + { + isModified = false; + e = m_SortedEdges; + while( e->NextInSEL ) + { + TEdge *eNext = e->NextInSEL; + IntPoint Pt; + if(e->Curr.X > eNext->Curr.X) + { + IntersectPoint(*e, *eNext, Pt); + if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY); + IntersectNode * newNode = new IntersectNode; + newNode->Edge1 = e; + newNode->Edge2 = eNext; + newNode->Pt = Pt; + m_IntersectList.push_back(newNode); + + SwapPositionsInSEL(e, eNext); + isModified = true; + } + else + e = eNext; + } + if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0; + else break; + } + while ( isModified ); + m_SortedEdges = 0; //important +} +//------------------------------------------------------------------------------ + + +void Clipper::ProcessIntersectList() +{ + for (size_t i = 0; i < m_IntersectList.size(); ++i) + { + IntersectNode* iNode = m_IntersectList[i]; + { + IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt); + SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 ); + } + delete iNode; + } + m_IntersectList.clear(); +} +//------------------------------------------------------------------------------ + +bool IntersectListSort(IntersectNode* node1, IntersectNode* node2) +{ + return node2->Pt.Y < node1->Pt.Y; +} +//------------------------------------------------------------------------------ + +inline bool EdgesAdjacent(const IntersectNode &inode) +{ + return (inode.Edge1->NextInSEL == inode.Edge2) || + (inode.Edge1->PrevInSEL == inode.Edge2); +} +//------------------------------------------------------------------------------ + +bool Clipper::FixupIntersectionOrder() +{ + //pre-condition: intersections are sorted Bottom-most first. + //Now it's crucial that intersections are made only between adjacent edges, + //so to ensure this the order of intersections may need adjusting ... + CopyAELToSEL(); + std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort); + size_t cnt = m_IntersectList.size(); + for (size_t i = 0; i < cnt; ++i) + { + if (!EdgesAdjacent(*m_IntersectList[i])) + { + size_t j = i + 1; + while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++; + if (j == cnt) return false; + std::swap(m_IntersectList[i], m_IntersectList[j]); + } + SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2); + } + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DoMaxima(TEdge *e) +{ + TEdge* eMaxPair = GetMaximaPairEx(e); + if (!eMaxPair) + { + if (e->OutIdx >= 0) + AddOutPt(e, e->Top); + DeleteFromAEL(e); + return; + } + + TEdge* eNext = e->NextInAEL; + while(eNext && eNext != eMaxPair) + { + IntersectEdges(e, eNext, e->Top); + SwapPositionsInAEL(e, eNext); + eNext = e->NextInAEL; + } + + if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned) + { + DeleteFromAEL(e); + DeleteFromAEL(eMaxPair); + } + else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 ) + { + if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top); + DeleteFromAEL(e); + DeleteFromAEL(eMaxPair); + } +#ifdef use_lines + else if (e->WindDelta == 0) + { + if (e->OutIdx >= 0) + { + AddOutPt(e, e->Top); + e->OutIdx = Unassigned; + } + DeleteFromAEL(e); + + if (eMaxPair->OutIdx >= 0) + { + AddOutPt(eMaxPair, e->Top); + eMaxPair->OutIdx = Unassigned; + } + DeleteFromAEL(eMaxPair); + } +#endif + else throw clipperException("DoMaxima error"); +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) +{ + TEdge* e = m_ActiveEdges; + while( e ) + { + //1. process maxima, treating them as if they're 'bent' horizontal edges, + // but exclude maxima with horizontal edges. nb: e can't be a horizontal. + bool IsMaximaEdge = IsMaxima(e, topY); + + if(IsMaximaEdge) + { + TEdge* eMaxPair = GetMaximaPairEx(e); + IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair)); + } + + if(IsMaximaEdge) + { + if (m_StrictSimple) m_Maxima.push_back(e->Top.X); + TEdge* ePrev = e->PrevInAEL; + DoMaxima(e); + if( !ePrev ) e = m_ActiveEdges; + else e = ePrev->NextInAEL; + } + else + { + //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ... + if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML)) + { + UpdateEdgeIntoAEL(e); + if (e->OutIdx >= 0) + AddOutPt(e, e->Bot); + AddEdgeToSEL(e); + } + else + { + e->Curr.X = TopX( *e, topY ); + e->Curr.Y = topY; +#ifdef use_xyz + e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0); +#endif + } + + //When StrictlySimple and 'e' is being touched by another edge, then + //make sure both edges have a vertex here ... + if (m_StrictSimple) + { + TEdge* ePrev = e->PrevInAEL; + if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) && + (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0)) + { + IntPoint pt = e->Curr; +#ifdef use_xyz + SetZ(pt, *ePrev, *e); +#endif + OutPt* op = AddOutPt(ePrev, pt); + OutPt* op2 = AddOutPt(e, pt); + AddJoin(op, op2, pt); //StrictlySimple (type-3) join + } + } + + e = e->NextInAEL; + } + } + + //3. Process horizontals at the Top of the scanbeam ... + m_Maxima.sort(); + ProcessHorizontals(); + m_Maxima.clear(); + + //4. Promote intermediate vertices ... + e = m_ActiveEdges; + while(e) + { + if(IsIntermediate(e, topY)) + { + OutPt* op = 0; + if( e->OutIdx >= 0 ) + op = AddOutPt(e, e->Top); + UpdateEdgeIntoAEL(e); + + //if output polygons share an edge, they'll need joining later ... + TEdge* ePrev = e->PrevInAEL; + TEdge* eNext = e->NextInAEL; + if (ePrev && ePrev->Curr.X == e->Bot.X && + ePrev->Curr.Y == e->Bot.Y && op && + ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y && + SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) && + (e->WindDelta != 0) && (ePrev->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(ePrev, e->Bot); + AddJoin(op, op2, e->Top); + } + else if (eNext && eNext->Curr.X == e->Bot.X && + eNext->Curr.Y == e->Bot.Y && op && + eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y && + SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) && + (e->WindDelta != 0) && (eNext->WindDelta != 0)) + { + OutPt* op2 = AddOutPt(eNext, e->Bot); + AddJoin(op, op2, e->Top); + } + } + e = e->NextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolyline(OutRec &outrec) +{ + OutPt *pp = outrec.Pts; + OutPt *lastPP = pp->Prev; + while (pp != lastPP) + { + pp = pp->Next; + if (pp->Pt == pp->Prev->Pt) + { + if (pp == lastPP) lastPP = pp->Prev; + OutPt *tmpPP = pp->Prev; + tmpPP->Next = pp->Next; + pp->Next->Prev = tmpPP; + delete pp; + pp = tmpPP; + } + } + + if (pp == pp->Prev) + { + DisposeOutPts(pp); + outrec.Pts = 0; + return; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolygon(OutRec &outrec) +{ + //FixupOutPolygon() - removes duplicate points and simplifies consecutive + //parallel edges by removing the middle vertex. + OutPt *lastOK = 0; + outrec.BottomPt = 0; + OutPt *pp = outrec.Pts; + bool preserveCol = m_PreserveCollinear || m_StrictSimple; + + for (;;) + { + if (pp->Prev == pp || pp->Prev == pp->Next) + { + DisposeOutPts(pp); + outrec.Pts = 0; + return; + } + + //test for duplicate points and collinear edges ... + if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) || + (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) && + (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt)))) + { + lastOK = 0; + OutPt *tmp = pp; + pp->Prev->Next = pp->Next; + pp->Next->Prev = pp->Prev; + pp = pp->Prev; + delete tmp; + } + else if (pp == lastOK) break; + else + { + if (!lastOK) lastOK = pp; + pp = pp->Next; + } + } + outrec.Pts = pp; +} +//------------------------------------------------------------------------------ + +int PointCount(OutPt *Pts) +{ + if (!Pts) return 0; + int result = 0; + OutPt* p = Pts; + do + { + result++; + p = p->Next; + } + while (p != Pts); + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult(Paths &polys) +{ + polys.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + if (!m_PolyOuts[i]->Pts) continue; + Path pg; + OutPt* p = m_PolyOuts[i]->Pts->Prev; + int cnt = PointCount(p); + if (cnt < 2) continue; + pg.reserve(cnt); + for (int i = 0; i < cnt; ++i) + { + pg.push_back(p->Pt); + p = p->Prev; + } + polys.push_back(pg); + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult2(PolyTree& polytree) +{ + polytree.Clear(); + polytree.AllNodes.reserve(m_PolyOuts.size()); + //add each output polygon/contour to polytree ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + int cnt = PointCount(outRec->Pts); + if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue; + FixHoleLinkage(*outRec); + PolyNode* pn = new PolyNode(); + //nb: polytree takes ownership of all the PolyNodes + polytree.AllNodes.push_back(pn); + outRec->PolyNd = pn; + pn->Parent = 0; + pn->Index = 0; + pn->Contour.reserve(cnt); + OutPt *op = outRec->Pts->Prev; + for (int j = 0; j < cnt; j++) + { + pn->Contour.push_back(op->Pt); + op = op->Prev; + } + } + + //fixup PolyNode links etc ... + polytree.Childs.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + if (!outRec->PolyNd) continue; + if (outRec->IsOpen) + { + outRec->PolyNd->m_IsOpen = true; + polytree.AddChild(*outRec->PolyNd); + } + else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd) + outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd); + else + polytree.AddChild(*outRec->PolyNd); + } +} +//------------------------------------------------------------------------------ + +void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) +{ + //just swap the contents (because fIntersectNodes is a single-linked-list) + IntersectNode inode = int1; //gets a copy of Int1 + int1.Edge1 = int2.Edge1; + int1.Edge2 = int2.Edge2; + int1.Pt = int2.Pt; + int2.Edge1 = inode.Edge1; + int2.Edge2 = inode.Edge2; + int2.Pt = inode.Pt; +} +//------------------------------------------------------------------------------ + +inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) +{ + if (e2.Curr.X == e1.Curr.X) + { + if (e2.Top.Y > e1.Top.Y) + return e2.Top.X < TopX(e1, e2.Top.Y); + else return e1.Top.X > TopX(e2, e1.Top.Y); + } + else return e2.Curr.X < e1.Curr.X; +} +//------------------------------------------------------------------------------ + +bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2, + cInt& Left, cInt& Right) +{ + if (a1 < a2) + { + if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);} + else {Left = std::max(a1,b2); Right = std::min(a2,b1);} + } + else + { + if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);} + else {Left = std::max(a2,b2); Right = std::min(a1,b1);} + } + return Left < Right; +} +//------------------------------------------------------------------------------ + +inline void UpdateOutPtIdxs(OutRec& outrec) +{ + OutPt* op = outrec.Pts; + do + { + op->Idx = outrec.Idx; + op = op->Prev; + } + while(op != outrec.Pts); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge) +{ + if(!m_ActiveEdges) + { + edge->PrevInAEL = 0; + edge->NextInAEL = 0; + m_ActiveEdges = edge; + } + else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge)) + { + edge->PrevInAEL = 0; + edge->NextInAEL = m_ActiveEdges; + m_ActiveEdges->PrevInAEL = edge; + m_ActiveEdges = edge; + } + else + { + if(!startEdge) startEdge = m_ActiveEdges; + while(startEdge->NextInAEL && + !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge)) + startEdge = startEdge->NextInAEL; + edge->NextInAEL = startEdge->NextInAEL; + if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge; + edge->PrevInAEL = startEdge; + startEdge->NextInAEL = edge; + } +} +//---------------------------------------------------------------------- + +OutPt* DupOutPt(OutPt* outPt, bool InsertAfter) +{ + OutPt* result = new OutPt; + result->Pt = outPt->Pt; + result->Idx = outPt->Idx; + if (InsertAfter) + { + result->Next = outPt->Next; + result->Prev = outPt; + outPt->Next->Prev = result; + outPt->Next = result; + } + else + { + result->Prev = outPt->Prev; + result->Next = outPt; + outPt->Prev->Next = result; + outPt->Prev = result; + } + return result; +} +//------------------------------------------------------------------------------ + +bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b, + const IntPoint Pt, bool DiscardLeft) +{ + Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight); + Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight); + if (Dir1 == Dir2) return false; + + //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we + //want Op1b to be on the Right. (And likewise with Op2 and Op2b.) + //So, to facilitate this while inserting Op1b and Op2b ... + //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b, + //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.) + if (Dir1 == dLeftToRight) + { + while (op1->Next->Pt.X <= Pt.X && + op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, !DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, !DiscardLeft); + } + } + else + { + while (op1->Next->Pt.X >= Pt.X && + op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y) + op1 = op1->Next; + if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next; + op1b = DupOutPt(op1, DiscardLeft); + if (op1b->Pt != Pt) + { + op1 = op1b; + op1->Pt = Pt; + op1b = DupOutPt(op1, DiscardLeft); + } + } + + if (Dir2 == dLeftToRight) + { + while (op2->Next->Pt.X <= Pt.X && + op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, !DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, !DiscardLeft); + }; + } else + { + while (op2->Next->Pt.X >= Pt.X && + op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y) + op2 = op2->Next; + if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next; + op2b = DupOutPt(op2, DiscardLeft); + if (op2b->Pt != Pt) + { + op2 = op2b; + op2->Pt = Pt; + op2b = DupOutPt(op2, DiscardLeft); + }; + }; + + if ((Dir1 == dLeftToRight) == DiscardLeft) + { + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + } + else + { + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + } + return true; +} +//------------------------------------------------------------------------------ + +bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2) +{ + OutPt *op1 = j->OutPt1, *op1b; + OutPt *op2 = j->OutPt2, *op2b; + + //There are 3 kinds of joins for output polygons ... + //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere + //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal). + //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same + //location at the Bottom of the overlapping segment (& Join.OffPt is above). + //3. StrictSimple joins where edges touch but are not collinear and where + //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point. + bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y); + + if (isHorizontal && (j->OffPt == j->OutPt1->Pt) && + (j->OffPt == j->OutPt2->Pt)) + { + //Strictly Simple join ... + if (outRec1 != outRec2) return false; + op1b = j->OutPt1->Next; + while (op1b != op1 && (op1b->Pt == j->OffPt)) + op1b = op1b->Next; + bool reverse1 = (op1b->Pt.Y > j->OffPt.Y); + op2b = j->OutPt2->Next; + while (op2b != op2 && (op2b->Pt == j->OffPt)) + op2b = op2b->Next; + bool reverse2 = (op2b->Pt.Y > j->OffPt.Y); + if (reverse1 == reverse2) return false; + if (reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } + else if (isHorizontal) + { + //treat horizontal joins differently to non-horizontal joins since with + //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt + //may be anywhere along the horizontal edge. + op1b = op1; + while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2) + op1 = op1->Prev; + while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2) + op1b = op1b->Next; + if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon' + + op2b = op2; + while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b) + op2 = op2->Prev; + while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1) + op2b = op2b->Next; + if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon' + + cInt Left, Right; + //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges + if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right)) + return false; + + //DiscardLeftSide: when overlapping edges are joined, a spike will created + //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up + //on the discard Side as either may still be needed for other joins ... + IntPoint Pt; + bool DiscardLeftSide; + if (op1->Pt.X >= Left && op1->Pt.X <= Right) + { + Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X); + } + else if (op2->Pt.X >= Left&& op2->Pt.X <= Right) + { + Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X); + } + else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right) + { + Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X; + } + else + { + Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X); + } + j->OutPt1 = op1; j->OutPt2 = op2; + return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide); + } else + { + //nb: For non-horizontal joins ... + // 1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y + // 2. Jr.OutPt1.Pt > Jr.OffPt.Y + + //make sure the polygons are correctly oriented ... + op1b = op1->Next; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next; + bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse1) + { + op1b = op1->Prev; + while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev; + if ((op1b->Pt.Y > op1->Pt.Y) || + !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false; + }; + op2b = op2->Next; + while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next; + bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)); + if (Reverse2) + { + op2b = op2->Prev; + while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev; + if ((op2b->Pt.Y > op2->Pt.Y) || + !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false; + } + + if ((op1b == op1) || (op2b == op2) || (op1b == op2b) || + ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false; + + if (Reverse1) + { + op1b = DupOutPt(op1, false); + op2b = DupOutPt(op2, true); + op1->Prev = op2; + op2->Next = op1; + op1b->Next = op2b; + op2b->Prev = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } else + { + op1b = DupOutPt(op1, true); + op2b = DupOutPt(op2, false); + op1->Next = op2; + op2->Prev = op1; + op1b->Prev = op2b; + op2b->Next = op1b; + j->OutPt1 = op1; + j->OutPt2 = op1b; + return true; + } + } +} +//---------------------------------------------------------------------- + +static OutRec* ParseFirstLeft(OutRec* FirstLeft) +{ + while (FirstLeft && !FirstLeft->Pts) + FirstLeft = FirstLeft->FirstLeft; + return FirstLeft; +} +//------------------------------------------------------------------------------ + +void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) +{ + //tests if NewOutRec contains the polygon before reassigning FirstLeft + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (outRec->Pts && firstLeft == OldOutRec) + { + if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) + outRec->FirstLeft = NewOutRec; + } + } +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec) +{ + //A polygon has split into two such that one is now the inner of the other. + //It's possible that these polygons now wrap around other polygons, so check + //every polygon that's also contained by OuterOutRec's FirstLeft container + //(including 0) to see if they've become inner to the new inner polygon ... + OutRec* orfl = OuterOutRec->FirstLeft; + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + + if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec) + continue; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec) + continue; + if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts)) + outRec->FirstLeft = InnerOutRec; + else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts)) + outRec->FirstLeft = OuterOutRec; + else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec) + outRec->FirstLeft = orfl; + } +} +//---------------------------------------------------------------------- +void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec) +{ + //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (outRec->Pts && firstLeft == OldOutRec) + outRec->FirstLeft = NewOutRec; + } +} +//---------------------------------------------------------------------- + +void Clipper::JoinCommonEdges() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + { + Join* join = m_Joins[i]; + + OutRec *outRec1 = GetOutRec(join->OutPt1->Idx); + OutRec *outRec2 = GetOutRec(join->OutPt2->Idx); + + if (!outRec1->Pts || !outRec2->Pts) continue; + if (outRec1->IsOpen || outRec2->IsOpen) continue; + + //get the polygon fragment with the correct hole state (FirstLeft) + //before calling JoinPoints() ... + OutRec *holeStateRec; + if (outRec1 == outRec2) holeStateRec = outRec1; + else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2; + else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1; + else holeStateRec = GetLowermostRec(outRec1, outRec2); + + if (!JoinPoints(join, outRec1, outRec2)) continue; + + if (outRec1 == outRec2) + { + //instead of joining two polygons, we've just created a new one by + //splitting one polygon into two. + outRec1->Pts = join->OutPt1; + outRec1->BottomPt = 0; + outRec2 = CreateOutRec(); + outRec2->Pts = join->OutPt2; + + //update all OutRec2.Pts Idx's ... + UpdateOutPtIdxs(*outRec2); + + if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts)) + { + //outRec1 contains outRec2 ... + outRec2->IsHole = !outRec1->IsHole; + outRec2->FirstLeft = outRec1; + + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + + if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0)) + ReversePolyPtLinks(outRec2->Pts); + + } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts)) + { + //outRec2 contains outRec1 ... + outRec2->IsHole = outRec1->IsHole; + outRec1->IsHole = !outRec2->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + outRec1->FirstLeft = outRec2; + + if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); + + if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0)) + ReversePolyPtLinks(outRec1->Pts); + } + else + { + //the 2 polygons are completely separate ... + outRec2->IsHole = outRec1->IsHole; + outRec2->FirstLeft = outRec1->FirstLeft; + + //fixup FirstLeft pointers that may need reassigning to OutRec2 + if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); + } + + } else + { + //joined 2 polygons together ... + + outRec2->Pts = 0; + outRec2->BottomPt = 0; + outRec2->Idx = outRec1->Idx; + + outRec1->IsHole = holeStateRec->IsHole; + if (holeStateRec == outRec2) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec2->FirstLeft = outRec1; + + if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1); + } + } +} + +//------------------------------------------------------------------------------ +// ClipperOffset support functions ... +//------------------------------------------------------------------------------ + +DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) +{ + if(pt2.X == pt1.X && pt2.Y == pt1.Y) + return DoublePoint(0, 0); + + double Dx = (double)(pt2.X - pt1.X); + double dy = (double)(pt2.Y - pt1.Y); + double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy ); + Dx *= f; + dy *= f; + return DoublePoint(dy, -Dx); +} + +//------------------------------------------------------------------------------ +// ClipperOffset class +//------------------------------------------------------------------------------ + +ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance) +{ + this->MiterLimit = miterLimit; + this->ArcTolerance = arcTolerance; + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +ClipperOffset::~ClipperOffset() +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Clear() +{ + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + delete m_polyNodes.Childs[i]; + m_polyNodes.Childs.clear(); + m_lowest.X = -1; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType) +{ + int highI = (int)path.size() - 1; + if (highI < 0) return; + PolyNode* newNode = new PolyNode(); + newNode->m_jointype = joinType; + newNode->m_endtype = endType; + + //strip duplicate points from path and also get index to the lowest point ... + if (endType == etClosedLine || endType == etClosedPolygon) + while (highI > 0 && path[0] == path[highI]) highI--; + newNode->Contour.reserve(highI + 1); + newNode->Contour.push_back(path[0]); + int j = 0, k = 0; + for (int i = 1; i <= highI; i++) + if (newNode->Contour[j] != path[i]) + { + j++; + newNode->Contour.push_back(path[i]); + if (path[i].Y > newNode->Contour[k].Y || + (path[i].Y == newNode->Contour[k].Y && + path[i].X < newNode->Contour[k].X)) k = j; + } + if (endType == etClosedPolygon && j < 2) + { + delete newNode; + return; + } + m_polyNodes.AddChild(*newNode); + + //if this path's lowest pt is lower than all the others then update m_lowest + if (endType != etClosedPolygon) return; + if (m_lowest.X < 0) + m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); + else + { + IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y]; + if (newNode->Contour[k].Y > ip.Y || + (newNode->Contour[k].Y == ip.Y && + newNode->Contour[k].X < ip.X)) + m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType) +{ + for (Paths::size_type i = 0; i < paths.size(); ++i) + AddPath(paths[i], joinType, endType); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::FixOrientations() +{ + //fixup orientations of all closed paths if the orientation of the + //closed path with the lowermost vertex is wrong ... + if (m_lowest.X >= 0 && + !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour)) + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon || + (node.m_endtype == etClosedLine && Orientation(node.Contour))) + ReversePath(node.Contour); + } + } else + { + for (int i = 0; i < m_polyNodes.ChildCount(); ++i) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedLine && !Orientation(node.Contour)) + ReversePath(node.Contour); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(Paths& solution, double delta) +{ + solution.clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + if (solution.size() > 0) solution.erase(solution.begin()); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::Execute(PolyTree& solution, double delta) +{ + solution.Clear(); + FixOrientations(); + DoOffset(delta); + + //now clean up 'corners' ... + Clipper clpr; + clpr.AddPaths(m_destPolys, ptSubject, true); + if (delta > 0) + { + clpr.Execute(ctUnion, solution, pftPositive, pftPositive); + } + else + { + IntRect r = clpr.GetBounds(); + Path outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPath(outer, ptSubject, true); + clpr.ReverseSolution(true); + clpr.Execute(ctUnion, solution, pftNegative, pftNegative); + //remove the outer PolyNode rectangle ... + if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0) + { + PolyNode* outerNode = solution.Childs[0]; + solution.Childs.reserve(outerNode->ChildCount()); + solution.Childs[0] = outerNode->Childs[0]; + solution.Childs[0]->Parent = outerNode->Parent; + for (int i = 1; i < outerNode->ChildCount(); ++i) + solution.AddChild(*outerNode->Childs[i]); + } + else + solution.Clear(); + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoOffset(double delta) +{ + m_destPolys.clear(); + m_delta = delta; + + //if Zero offset, just copy any CLOSED polygons to m_p and return ... + if (NEAR_ZERO(delta)) + { + m_destPolys.reserve(m_polyNodes.ChildCount()); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + if (node.m_endtype == etClosedPolygon) + m_destPolys.push_back(node.Contour); + } + return; + } + + //see offset_triginometry3.svg in the documentation folder ... + if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit); + else m_miterLim = 0.5; + + double y; + if (ArcTolerance <= 0.0) y = def_arc_tolerance; + else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance) + y = std::fabs(delta) * def_arc_tolerance; + else y = ArcTolerance; + //see offset_triginometry2.svg in the documentation folder ... + double steps = pi / std::acos(1 - y / std::fabs(delta)); + if (steps > std::fabs(delta) * pi) + steps = std::fabs(delta) * pi; //ie excessive precision check + m_sin = std::sin(two_pi / steps); + m_cos = std::cos(two_pi / steps); + m_StepsPerRad = steps / two_pi; + if (delta < 0.0) m_sin = -m_sin; + + m_destPolys.reserve(m_polyNodes.ChildCount() * 2); + for (int i = 0; i < m_polyNodes.ChildCount(); i++) + { + PolyNode& node = *m_polyNodes.Childs[i]; + m_srcPoly = node.Contour; + + int len = (int)m_srcPoly.size(); + if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon))) + continue; + + m_destPoly.clear(); + if (len == 1) + { + if (node.m_jointype == jtRound) + { + double X = 1.0, Y = 0.0; + for (cInt j = 1; j <= steps; j++) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + double X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + } + else + { + double X = -1.0, Y = -1.0; + for (int j = 0; j < 4; ++j) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[0].X + X * delta), + Round(m_srcPoly[0].Y + Y * delta))); + if (X < 0) X = 1; + else if (Y < 0) Y = 1; + else X = -1; + } + } + m_destPolys.push_back(m_destPoly); + continue; + } + //build m_normals ... + m_normals.clear(); + m_normals.reserve(len); + for (int j = 0; j < len - 1; ++j) + m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1])); + if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon) + m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0])); + else + m_normals.push_back(DoublePoint(m_normals[len - 2])); + + if (node.m_endtype == etClosedPolygon) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else if (node.m_endtype == etClosedLine) + { + int k = len - 1; + for (int j = 0; j < len; ++j) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + m_destPoly.clear(); + //re-build m_normals ... + DoublePoint n = m_normals[len -1]; + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-n.X, -n.Y); + k = 0; + for (int j = len - 1; j >= 0; j--) + OffsetPoint(j, k, node.m_jointype); + m_destPolys.push_back(m_destPoly); + } + else + { + int k = 0; + for (int j = 1; j < len - 1; ++j) + OffsetPoint(j, k, node.m_jointype); + + IntPoint pt1; + if (node.m_endtype == etOpenButt) + { + int j = len - 1; + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X * + delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + int j = len - 1; + k = len - 2; + m_sinA = 0; + m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y); + if (node.m_endtype == etOpenSquare) + DoSquare(j, k); + else + DoRound(j, k); + } + + //re-build m_normals ... + for (int j = len - 1; j > 0; j--) + m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y); + m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y); + + k = len - 1; + for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype); + + if (node.m_endtype == etOpenButt) + { + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta), + (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta)); + m_destPoly.push_back(pt1); + } + else + { + k = 1; + m_sinA = 0; + if (node.m_endtype == etOpenSquare) + DoSquare(0, 1); + else + DoRound(0, 1); + } + m_destPolys.push_back(m_destPoly); + } + } +} +//------------------------------------------------------------------------------ + +void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype) +{ + //cross product ... + m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y); + if (std::fabs(m_sinA * m_delta) < 1.0) + { + //dot product ... + double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y ); + if (cosA > 0) // angle => 0 degrees + { + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); + return; + } + //else angle => 180 degrees + } + else if (m_sinA > 1.0) m_sinA = 1.0; + else if (m_sinA < -1.0) m_sinA = -1.0; + + if (m_sinA * m_delta < 0) + { + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta))); + m_destPoly.push_back(m_srcPoly[j]); + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); + } + else + switch (jointype) + { + case jtMiter: + { + double r = 1 + (m_normals[j].X * m_normals[k].X + + m_normals[j].Y * m_normals[k].Y); + if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k); + break; + } + case jtSquare: DoSquare(j, k); break; + case jtRound: DoRound(j, k); break; + } + k = j; +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoSquare(int j, int k) +{ + double dx = std::tan(std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx)))); + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)), + Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx)))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoMiter(int j, int k, double r) +{ + double q = m_delta / r; + m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q), + Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q))); +} +//------------------------------------------------------------------------------ + +void ClipperOffset::DoRound(int j, int k) +{ + double a = std::atan2(m_sinA, + m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y); + int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1); + + double X = m_normals[k].X, Y = m_normals[k].Y, X2; + for (int i = 0; i < steps; ++i) + { + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + X * m_delta), + Round(m_srcPoly[j].Y + Y * m_delta))); + X2 = X; + X = X * m_cos - m_sin * Y; + Y = X2 * m_sin + Y * m_cos; + } + m_destPoly.push_back(IntPoint( + Round(m_srcPoly[j].X + m_normals[j].X * m_delta), + Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta))); +} + +//------------------------------------------------------------------------------ +// Miscellaneous public functions +//------------------------------------------------------------------------------ + +void Clipper::DoSimplePolygons() +{ + PolyOutList::size_type i = 0; + while (i < m_PolyOuts.size()) + { + OutRec* outrec = m_PolyOuts[i++]; + OutPt* op = outrec->Pts; + if (!op || outrec->IsOpen) continue; + do //for each Pt in Polygon until duplicate found do ... + { + OutPt* op2 = op->Next; + while (op2 != outrec->Pts) + { + if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op) + { + //split the polygon into two ... + OutPt* op3 = op->Prev; + OutPt* op4 = op2->Prev; + op->Prev = op4; + op4->Next = op; + op2->Prev = op3; + op3->Next = op2; + + outrec->Pts = op; + OutRec* outrec2 = CreateOutRec(); + outrec2->Pts = op2; + UpdateOutPtIdxs(*outrec2); + if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts)) + { + //OutRec2 is contained by OutRec1 ... + outrec2->IsHole = !outrec->IsHole; + outrec2->FirstLeft = outrec; + if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec); + } + else + if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts)) + { + //OutRec1 is contained by OutRec2 ... + outrec2->IsHole = outrec->IsHole; + outrec->IsHole = !outrec2->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + outrec->FirstLeft = outrec2; + if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2); + } + else + { + //the 2 polygons are separate ... + outrec2->IsHole = outrec->IsHole; + outrec2->FirstLeft = outrec->FirstLeft; + if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2); + } + op2 = op; //ie get ready for the Next iteration + } + op2 = op2->Next; + } + op = op->Next; + } + while (op != outrec->Pts); + } +} +//------------------------------------------------------------------------------ + +void ReversePath(Path& p) +{ + std::reverse(p.begin(), p.end()); +} +//------------------------------------------------------------------------------ + +void ReversePaths(Paths& p) +{ + for (Paths::size_type i = 0; i < p.size(); ++i) + ReversePath(p[i]); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPath(in_poly, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType) +{ + Clipper c; + c.StrictlySimple(true); + c.AddPaths(in_polys, ptSubject, true); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(Paths &polys, PolyFillType fillType) +{ + SimplifyPolygons(polys, polys, fillType); +} +//------------------------------------------------------------------------------ + +inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) +{ + double Dx = ((double)pt1.X - pt2.X); + double dy = ((double)pt1.Y - pt2.Y); + return (Dx*Dx + dy*dy); +} +//------------------------------------------------------------------------------ + +double DistanceFromLineSqrd( + const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2) +{ + //The equation of a line in general form (Ax + By + C = 0) + //given 2 points (x�,y�) & (x�,y�) is ... + //(y� - y�)x + (x� - x�)y + (y� - y�)x� - (x� - x�)y� = 0 + //A = (y� - y�); B = (x� - x�); C = (y� - y�)x� - (x� - x�)y� + //perpendicular distance of point (x�,y�) = (Ax� + By� + C)/Sqrt(A� + B�) + //see http://en.wikipedia.org/wiki/Perpendicular_distance + double A = double(ln1.Y - ln2.Y); + double B = double(ln2.X - ln1.X); + double C = A * ln1.X + B * ln1.Y; + C = A * pt.X + B * pt.Y - C; + return (C * C) / (A * A + B * B); +} +//--------------------------------------------------------------------------- + +bool SlopesNearCollinear(const IntPoint& pt1, + const IntPoint& pt2, const IntPoint& pt3, double distSqrd) +{ + //this function is more accurate when the point that's geometrically + //between the other 2 points is the one that's tested for distance. + //ie makes it more likely to pick up 'spikes' ... + if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y)) + { + if ((pt1.X > pt2.X) == (pt1.X < pt3.X)) + return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; + else if ((pt2.X > pt1.X) == (pt2.X < pt3.X)) + return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; + else + return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; + } + else + { + if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y)) + return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd; + else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y)) + return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd; + else + return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd; + } +} +//------------------------------------------------------------------------------ + +bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) +{ + double Dx = (double)pt1.X - pt2.X; + double dy = (double)pt1.Y - pt2.Y; + return ((Dx * Dx) + (dy * dy) <= distSqrd); +} +//------------------------------------------------------------------------------ + +OutPt* ExcludeOp(OutPt* op) +{ + OutPt* result = op->Prev; + result->Next = op->Next; + op->Next->Prev = result; + result->Idx = 0; + return result; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance) +{ + //distance = proximity in units/pixels below which vertices + //will be stripped. Default ~= sqrt(2). + + size_t size = in_poly.size(); + + if (size == 0) + { + out_poly.clear(); + return; + } + + OutPt* outPts = new OutPt[size]; + for (size_t i = 0; i < size; ++i) + { + outPts[i].Pt = in_poly[i]; + outPts[i].Next = &outPts[(i + 1) % size]; + outPts[i].Next->Prev = &outPts[i]; + outPts[i].Idx = 0; + } + + double distSqrd = distance * distance; + OutPt* op = &outPts[0]; + while (op->Idx == 0 && op->Next != op->Prev) + { + if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd)) + { + ExcludeOp(op->Next); + op = ExcludeOp(op); + size -= 2; + } + else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd)) + { + op = ExcludeOp(op); + size--; + } + else + { + op->Idx = 1; + op = op->Next; + } + } + + if (size < 3) size = 0; + out_poly.resize(size); + for (size_t i = 0; i < size; ++i) + { + out_poly[i] = op->Pt; + op = op->Next; + } + delete [] outPts; +} +//------------------------------------------------------------------------------ + +void CleanPolygon(Path& poly, double distance) +{ + CleanPolygon(poly, poly, distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance) +{ + out_polys.resize(in_polys.size()); + for (Paths::size_type i = 0; i < in_polys.size(); ++i) + CleanPolygon(in_polys[i], out_polys[i], distance); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(Paths& polys, double distance) +{ + CleanPolygons(polys, polys, distance); +} +//------------------------------------------------------------------------------ + +void Minkowski(const Path& poly, const Path& path, + Paths& solution, bool isSum, bool isClosed) +{ + int delta = (isClosed ? 1 : 0); + size_t polyCnt = poly.size(); + size_t pathCnt = path.size(); + Paths pp; + pp.reserve(pathCnt); + if (isSum) + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y)); + pp.push_back(p); + } + else + for (size_t i = 0; i < pathCnt; ++i) + { + Path p; + p.reserve(polyCnt); + for (size_t j = 0; j < poly.size(); ++j) + p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y)); + pp.push_back(p); + } + + solution.clear(); + solution.reserve((pathCnt + delta) * (polyCnt + 1)); + for (size_t i = 0; i < pathCnt - 1 + delta; ++i) + for (size_t j = 0; j < polyCnt; ++j) + { + Path quad; + quad.reserve(4); + quad.push_back(pp[i % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]); + quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]); + quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]); + if (!Orientation(quad)) ReversePath(quad); + solution.push_back(quad); + } +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) +{ + Minkowski(pattern, path, solution, true, pathIsClosed); + Clipper c; + c.AddPaths(solution, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +void TranslatePath(const Path& input, Path& output, const IntPoint delta) +{ + //precondition: input != output + output.resize(input.size()); + for (size_t i = 0; i < input.size(); ++i) + output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y); +} +//------------------------------------------------------------------------------ + +void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed) +{ + Clipper c; + for (size_t i = 0; i < paths.size(); ++i) + { + Paths tmp; + Minkowski(pattern, paths[i], tmp, true, pathIsClosed); + c.AddPaths(tmp, ptSubject, true); + if (pathIsClosed) + { + Path tmp2; + TranslatePath(paths[i], tmp2, pattern[0]); + c.AddPath(tmp2, ptClip, true); + } + } + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution) +{ + Minkowski(poly1, poly2, solution, false, true); + Clipper c; + c.AddPaths(solution, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); +} +//------------------------------------------------------------------------------ + +enum NodeType {ntAny, ntOpen, ntClosed}; + +void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths) +{ + bool match = true; + if (nodetype == ntClosed) match = !polynode.IsOpen(); + else if (nodetype == ntOpen) return; + + if (!polynode.Contour.empty() && match) + paths.push_back(polynode.Contour); + for (int i = 0; i < polynode.ChildCount(); ++i) + AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths); +} +//------------------------------------------------------------------------------ + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPaths(polytree, ntAny, paths); +} +//------------------------------------------------------------------------------ + +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + AddPolyNodeToPaths(polytree, ntClosed, paths); +} +//------------------------------------------------------------------------------ + +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths) +{ + paths.resize(0); + paths.reserve(polytree.Total()); + //Open paths are top level only, so ... + for (int i = 0; i < polytree.ChildCount(); ++i) + if (polytree.Childs[i]->IsOpen()) + paths.push_back(polytree.Childs[i]->Contour); +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const IntPoint &p) +{ + s << "(" << p.X << "," << p.Y << ")"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Path &p) +{ + if (p.empty()) return s; + Path::size_type last = p.size() -1; + for (Path::size_type i = 0; i < last; i++) + s << "(" << p[i].X << "," << p[i].Y << "), "; + s << "(" << p[last].X << "," << p[last].Y << ")\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, const Paths &p) +{ + for (Paths::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +} //ClipperLib namespace diff --git a/libs/clipper/include/clipper.hpp b/libs/clipper/clipper/clipper.hpp similarity index 95% rename from libs/clipper/include/clipper.hpp rename to libs/clipper/clipper/clipper.hpp index df1f8137d..33043fdb6 100644 --- a/libs/clipper/include/clipper.hpp +++ b/libs/clipper/clipper/clipper.hpp @@ -1,406 +1,406 @@ -/******************************************************************************* -* * -* Author : Angus Johnson * -* Version : 6.4.2 * -* Date : 27 February 2017 * -* Website : http://www.angusj.com * -* Copyright : Angus Johnson 2010-2017 * -* * -* License: * -* Use, modification & distribution is subject to Boost Software License Ver 1. * -* http://www.boost.org/LICENSE_1_0.txt * -* * -* Attributions: * -* The code in this library is an extension of Bala Vatti's clipping algorithm: * -* "A generic solution to polygon clipping" * -* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * -* http://portal.acm.org/citation.cfm?id=129906 * -* * -* Computer graphics and geometric modeling: implementation and algorithms * -* By Max K. Agoston * -* Springer; 1 edition (January 4, 2005) * -* http://books.google.com/books?q=vatti+clipping+agoston * -* * -* See also: * -* "Polygon Offsetting by Computing Winding Numbers" * -* Paper no. DETC2005-85513 pp. 565-575 * -* ASME 2005 International Design Engineering Technical Conferences * -* and Computers and Information in Engineering Conference (IDETC/CIE2005) * -* September 24-28, 2005 , Long Beach, California, USA * -* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * -* * -*******************************************************************************/ - -#ifndef clipper_hpp -#define clipper_hpp - -#define CLIPPER_VERSION "6.4.2" - -//use_int32: When enabled 32bit ints are used instead of 64bit ints. This -//improve performance but coordinate values are limited to the range +/- 46340 -//#define use_int32 - -//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. -//#define use_xyz - -//use_lines: Enables line clipping. Adds a very minor cost to performance. -#define use_lines - -//use_deprecated: Enables temporary support for the obsolete functions -//#define use_deprecated - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ClipperLib { - -enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; -enum PolyType { ptSubject, ptClip }; -//By far the most widely used winding rules for polygon filling are -//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) -//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) -//see http://glprogramming.com/red/chapter11.html -enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; - -#ifdef use_int32 - typedef int cInt; - static cInt const loRange = 0x7FFF; - static cInt const hiRange = 0x7FFF; -#else - typedef signed long long cInt; - static cInt const loRange = 0x3FFFFFFF; - static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; - typedef signed long long long64; //used by Int128 class - typedef unsigned long long ulong64; - -#endif - -struct IntPoint { - cInt X; - cInt Y; -#ifdef use_xyz - cInt Z; - IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; -#else - IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; -#endif - - friend inline bool operator== (const IntPoint& a, const IntPoint& b) - { - return a.X == b.X && a.Y == b.Y; - } - friend inline bool operator!= (const IntPoint& a, const IntPoint& b) - { - return a.X != b.X || a.Y != b.Y; - } -}; -//------------------------------------------------------------------------------ - -typedef std::vector< IntPoint > Path; -typedef std::vector< Path > Paths; - -inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} -inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} - -std::ostream& operator <<(std::ostream &s, const IntPoint &p); -std::ostream& operator <<(std::ostream &s, const Path &p); -std::ostream& operator <<(std::ostream &s, const Paths &p); - -struct DoublePoint -{ - double X; - double Y; - DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} - DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} -}; -//------------------------------------------------------------------------------ - -#ifdef use_xyz -typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); -#endif - -enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; -enum JoinType {jtSquare, jtRound, jtMiter}; -enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; - -class PolyNode; -typedef std::vector< PolyNode* > PolyNodes; - -class PolyNode -{ -public: - PolyNode(); - virtual ~PolyNode(){}; - Path Contour; - PolyNodes Childs; - PolyNode* Parent; - PolyNode* GetNext() const; - bool IsHole() const; - bool IsOpen() const; - int ChildCount() const; -private: - //PolyNode& operator =(PolyNode& other); - unsigned Index; //node index in Parent.Childs - bool m_IsOpen; - JoinType m_jointype; - EndType m_endtype; - PolyNode* GetNextSiblingUp() const; - void AddChild(PolyNode& child); - friend class Clipper; //to access Index - friend class ClipperOffset; -}; - -class PolyTree: public PolyNode -{ -public: - ~PolyTree(){ Clear(); }; - PolyNode* GetFirst() const; - void Clear(); - int Total() const; -private: - //PolyTree& operator =(PolyTree& other); - PolyNodes AllNodes; - friend class Clipper; //to access AllNodes -}; - -bool Orientation(const Path &poly); -double Area(const Path &poly); -int PointInPolygon(const IntPoint &pt, const Path &path); - -void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); -void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); -void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); - -void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); -void CleanPolygon(Path& poly, double distance = 1.415); -void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); -void CleanPolygons(Paths& polys, double distance = 1.415); - -void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); -void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); -void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); - -void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); -void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); -void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); - -void ReversePath(Path& p); -void ReversePaths(Paths& p); - -struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; - -//enums that are used internally ... -enum EdgeSide { esLeft = 1, esRight = 2}; - -//forward declarations (for stuff used internally) ... -struct TEdge; -struct IntersectNode; -struct LocalMinimum; -struct OutPt; -struct OutRec; -struct Join; - -typedef std::vector < OutRec* > PolyOutList; -typedef std::vector < TEdge* > EdgeList; -typedef std::vector < Join* > JoinList; -typedef std::vector < IntersectNode* > IntersectList; - -//------------------------------------------------------------------------------ - -//ClipperBase is the ancestor to the Clipper class. It should not be -//instantiated directly. This class simply abstracts the conversion of sets of -//polygon coordinates into edge objects that are stored in a LocalMinima list. -class ClipperBase -{ -public: - ClipperBase(); - virtual ~ClipperBase(); - virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); - bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); - virtual void Clear(); - IntRect GetBounds(); - bool PreserveCollinear() {return m_PreserveCollinear;}; - void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; -protected: - void DisposeLocalMinimaList(); - TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); - virtual void Reset(); - TEdge* ProcessBound(TEdge* E, bool IsClockwise); - void InsertScanbeam(const cInt Y); - bool PopScanbeam(cInt &Y); - bool LocalMinimaPending(); - bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); - OutRec* CreateOutRec(); - void DisposeAllOutRecs(); - void DisposeOutRec(PolyOutList::size_type index); - void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); - void DeleteFromAEL(TEdge *e); - void UpdateEdgeIntoAEL(TEdge *&e); - - typedef std::vector MinimaList; - MinimaList::iterator m_CurrentLM; - MinimaList m_MinimaList; - - bool m_UseFullRange; - EdgeList m_edges; - bool m_PreserveCollinear; - bool m_HasOpenPaths; - PolyOutList m_PolyOuts; - TEdge *m_ActiveEdges; - - typedef std::priority_queue ScanbeamList; - ScanbeamList m_Scanbeam; -}; -//------------------------------------------------------------------------------ - -class Clipper : public virtual ClipperBase -{ -public: - Clipper(int initOptions = 0); - bool Execute(ClipType clipType, - Paths &solution, - PolyFillType fillType = pftEvenOdd); - bool Execute(ClipType clipType, - Paths &solution, - PolyFillType subjFillType, - PolyFillType clipFillType); - bool Execute(ClipType clipType, - PolyTree &polytree, - PolyFillType fillType = pftEvenOdd); - bool Execute(ClipType clipType, - PolyTree &polytree, - PolyFillType subjFillType, - PolyFillType clipFillType); - bool ReverseSolution() { return m_ReverseOutput; }; - void ReverseSolution(bool value) {m_ReverseOutput = value;}; - bool StrictlySimple() {return m_StrictSimple;}; - void StrictlySimple(bool value) {m_StrictSimple = value;}; - //set the callback function for z value filling on intersections (otherwise Z is 0) -#ifdef use_xyz - void ZFillFunction(ZFillCallback zFillFunc); -#endif -protected: - virtual bool ExecuteInternal(); -private: - JoinList m_Joins; - JoinList m_GhostJoins; - IntersectList m_IntersectList; - ClipType m_ClipType; - typedef std::list MaximaList; - MaximaList m_Maxima; - TEdge *m_SortedEdges; - bool m_ExecuteLocked; - PolyFillType m_ClipFillType; - PolyFillType m_SubjFillType; - bool m_ReverseOutput; - bool m_UsingPolyTree; - bool m_StrictSimple; -#ifdef use_xyz - ZFillCallback m_ZFill; //custom callback -#endif - void SetWindingCount(TEdge& edge); - bool IsEvenOddFillType(const TEdge& edge) const; - bool IsEvenOddAltFillType(const TEdge& edge) const; - void InsertLocalMinimaIntoAEL(const cInt botY); - void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); - void AddEdgeToSEL(TEdge *edge); - bool PopEdgeFromSEL(TEdge *&edge); - void CopyAELToSEL(); - void DeleteFromSEL(TEdge *e); - void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); - bool IsContributing(const TEdge& edge) const; - bool IsTopHorz(const cInt XPos); - void DoMaxima(TEdge *e); - void ProcessHorizontals(); - void ProcessHorizontal(TEdge *horzEdge); - void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); - OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); - OutRec* GetOutRec(int idx); - void AppendPolygon(TEdge *e1, TEdge *e2); - void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); - OutPt* AddOutPt(TEdge *e, const IntPoint &pt); - OutPt* GetLastOutPt(TEdge *e); - bool ProcessIntersections(const cInt topY); - void BuildIntersectList(const cInt topY); - void ProcessIntersectList(); - void ProcessEdgesAtTopOfScanbeam(const cInt topY); - void BuildResult(Paths& polys); - void BuildResult2(PolyTree& polytree); - void SetHoleState(TEdge *e, OutRec *outrec); - void DisposeIntersectNodes(); - bool FixupIntersectionOrder(); - void FixupOutPolygon(OutRec &outrec); - void FixupOutPolyline(OutRec &outrec); - bool IsHole(TEdge *e); - bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); - void FixHoleLinkage(OutRec &outrec); - void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); - void ClearJoins(); - void ClearGhostJoins(); - void AddGhostJoin(OutPt *op, const IntPoint offPt); - bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); - void JoinCommonEdges(); - void DoSimplePolygons(); - void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); - void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); - void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); -#ifdef use_xyz - void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); -#endif -}; -//------------------------------------------------------------------------------ - -class ClipperOffset -{ -public: - ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); - ~ClipperOffset(); - void AddPath(const Path& path, JoinType joinType, EndType endType); - void AddPaths(const Paths& paths, JoinType joinType, EndType endType); - void Execute(Paths& solution, double delta); - void Execute(PolyTree& solution, double delta); - void Clear(); - double MiterLimit; - double ArcTolerance; -private: - Paths m_destPolys; - Path m_srcPoly; - Path m_destPoly; - std::vector m_normals; - double m_delta, m_sinA, m_sin, m_cos; - double m_miterLim, m_StepsPerRad; - IntPoint m_lowest; - PolyNode m_polyNodes; - - void FixOrientations(); - void DoOffset(double delta); - void OffsetPoint(int j, int& k, JoinType jointype); - void DoSquare(int j, int k); - void DoMiter(int j, int k, double r); - void DoRound(int j, int k); -}; -//------------------------------------------------------------------------------ - -class clipperException : public std::exception -{ - public: - clipperException(const char* description): m_descr(description) {} - virtual ~clipperException() throw() {} - virtual const char* what() const throw() {return m_descr.c_str();} - private: - std::string m_descr; -}; -//------------------------------------------------------------------------------ - -} //ClipperLib namespace - -#endif //clipper_hpp - - +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 6.4.2 * +* Date : 27 February 2017 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2017 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +#ifndef clipper_hpp +#define clipper_hpp + +#define CLIPPER_VERSION "6.4.2" + +//use_int32: When enabled 32bit ints are used instead of 64bit ints. This +//improve performance but coordinate values are limited to the range +/- 46340 +//#define use_int32 + +//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance. +//#define use_xyz + +//use_lines: Enables line clipping. Adds a very minor cost to performance. +#define use_lines + +//use_deprecated: Enables temporary support for the obsolete functions +//#define use_deprecated + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; +enum PolyType { ptSubject, ptClip }; +//By far the most widely used winding rules for polygon filling are +//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) +//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) +//see http://glprogramming.com/red/chapter11.html +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; + +#ifdef use_int32 + typedef int cInt; + static cInt const loRange = 0x7FFF; + static cInt const hiRange = 0x7FFF; +#else + typedef signed long long cInt; + static cInt const loRange = 0x3FFFFFFF; + static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL; + typedef signed long long long64; //used by Int128 class + typedef unsigned long long ulong64; + +#endif + +struct IntPoint { + cInt X; + cInt Y; +#ifdef use_xyz + cInt Z; + IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {}; +#else + IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {}; +#endif + + friend inline bool operator== (const IntPoint& a, const IntPoint& b) + { + return a.X == b.X && a.Y == b.Y; + } + friend inline bool operator!= (const IntPoint& a, const IntPoint& b) + { + return a.X != b.X || a.Y != b.Y; + } +}; +//------------------------------------------------------------------------------ + +typedef std::vector< IntPoint > Path; +typedef std::vector< Path > Paths; + +inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;} +inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;} + +std::ostream& operator <<(std::ostream &s, const IntPoint &p); +std::ostream& operator <<(std::ostream &s, const Path &p); +std::ostream& operator <<(std::ostream &s, const Paths &p); + +struct DoublePoint +{ + double X; + double Y; + DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} + DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {} +}; +//------------------------------------------------------------------------------ + +#ifdef use_xyz +typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt); +#endif + +enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4}; +enum JoinType {jtSquare, jtRound, jtMiter}; +enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound}; + +class PolyNode; +typedef std::vector< PolyNode* > PolyNodes; + +class PolyNode +{ +public: + PolyNode(); + virtual ~PolyNode(){}; + Path Contour; + PolyNodes Childs; + PolyNode* Parent; + PolyNode* GetNext() const; + bool IsHole() const; + bool IsOpen() const; + int ChildCount() const; +private: + //PolyNode& operator =(PolyNode& other); + unsigned Index; //node index in Parent.Childs + bool m_IsOpen; + JoinType m_jointype; + EndType m_endtype; + PolyNode* GetNextSiblingUp() const; + void AddChild(PolyNode& child); + friend class Clipper; //to access Index + friend class ClipperOffset; +}; + +class PolyTree: public PolyNode +{ +public: + ~PolyTree(){ Clear(); }; + PolyNode* GetFirst() const; + void Clear(); + int Total() const; +private: + //PolyTree& operator =(PolyTree& other); + PolyNodes AllNodes; + friend class Clipper; //to access AllNodes +}; + +bool Orientation(const Path &poly); +double Area(const Path &poly); +int PointInPolygon(const IntPoint &pt, const Path &path); + +void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd); + +void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415); +void CleanPolygon(Path& poly, double distance = 1.415); +void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415); +void CleanPolygons(Paths& polys, double distance = 1.415); + +void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed); +void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed); +void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution); + +void PolyTreeToPaths(const PolyTree& polytree, Paths& paths); +void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths); +void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths); + +void ReversePath(Path& p); +void ReversePaths(Paths& p); + +struct IntRect { cInt left; cInt top; cInt right; cInt bottom; }; + +//enums that are used internally ... +enum EdgeSide { esLeft = 1, esRight = 2}; + +//forward declarations (for stuff used internally) ... +struct TEdge; +struct IntersectNode; +struct LocalMinimum; +struct OutPt; +struct OutRec; +struct Join; + +typedef std::vector < OutRec* > PolyOutList; +typedef std::vector < TEdge* > EdgeList; +typedef std::vector < Join* > JoinList; +typedef std::vector < IntersectNode* > IntersectList; + +//------------------------------------------------------------------------------ + +//ClipperBase is the ancestor to the Clipper class. It should not be +//instantiated directly. This class simply abstracts the conversion of sets of +//polygon coordinates into edge objects that are stored in a LocalMinima list. +class ClipperBase +{ +public: + ClipperBase(); + virtual ~ClipperBase(); + virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed); + bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed); + virtual void Clear(); + IntRect GetBounds(); + bool PreserveCollinear() {return m_PreserveCollinear;}; + void PreserveCollinear(bool value) {m_PreserveCollinear = value;}; +protected: + void DisposeLocalMinimaList(); + TEdge* AddBoundsToLML(TEdge *e, bool IsClosed); + virtual void Reset(); + TEdge* ProcessBound(TEdge* E, bool IsClockwise); + void InsertScanbeam(const cInt Y); + bool PopScanbeam(cInt &Y); + bool LocalMinimaPending(); + bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin); + OutRec* CreateOutRec(); + void DisposeAllOutRecs(); + void DisposeOutRec(PolyOutList::size_type index); + void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); + void DeleteFromAEL(TEdge *e); + void UpdateEdgeIntoAEL(TEdge *&e); + + typedef std::vector MinimaList; + MinimaList::iterator m_CurrentLM; + MinimaList m_MinimaList; + + bool m_UseFullRange; + EdgeList m_edges; + bool m_PreserveCollinear; + bool m_HasOpenPaths; + PolyOutList m_PolyOuts; + TEdge *m_ActiveEdges; + + typedef std::priority_queue ScanbeamList; + ScanbeamList m_Scanbeam; +}; +//------------------------------------------------------------------------------ + +class Clipper : public virtual ClipperBase +{ +public: + Clipper(int initOptions = 0); + bool Execute(ClipType clipType, + Paths &solution, + PolyFillType fillType = pftEvenOdd); + bool Execute(ClipType clipType, + Paths &solution, + PolyFillType subjFillType, + PolyFillType clipFillType); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType fillType = pftEvenOdd); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType subjFillType, + PolyFillType clipFillType); + bool ReverseSolution() { return m_ReverseOutput; }; + void ReverseSolution(bool value) {m_ReverseOutput = value;}; + bool StrictlySimple() {return m_StrictSimple;}; + void StrictlySimple(bool value) {m_StrictSimple = value;}; + //set the callback function for z value filling on intersections (otherwise Z is 0) +#ifdef use_xyz + void ZFillFunction(ZFillCallback zFillFunc); +#endif +protected: + virtual bool ExecuteInternal(); +private: + JoinList m_Joins; + JoinList m_GhostJoins; + IntersectList m_IntersectList; + ClipType m_ClipType; + typedef std::list MaximaList; + MaximaList m_Maxima; + TEdge *m_SortedEdges; + bool m_ExecuteLocked; + PolyFillType m_ClipFillType; + PolyFillType m_SubjFillType; + bool m_ReverseOutput; + bool m_UsingPolyTree; + bool m_StrictSimple; +#ifdef use_xyz + ZFillCallback m_ZFill; //custom callback +#endif + void SetWindingCount(TEdge& edge); + bool IsEvenOddFillType(const TEdge& edge) const; + bool IsEvenOddAltFillType(const TEdge& edge) const; + void InsertLocalMinimaIntoAEL(const cInt botY); + void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge); + void AddEdgeToSEL(TEdge *edge); + bool PopEdgeFromSEL(TEdge *&edge); + void CopyAELToSEL(); + void DeleteFromSEL(TEdge *e); + void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); + bool IsContributing(const TEdge& edge) const; + bool IsTopHorz(const cInt XPos); + void DoMaxima(TEdge *e); + void ProcessHorizontals(); + void ProcessHorizontal(TEdge *horzEdge); + void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutRec* GetOutRec(int idx); + void AppendPolygon(TEdge *e1, TEdge *e2); + void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); + OutPt* AddOutPt(TEdge *e, const IntPoint &pt); + OutPt* GetLastOutPt(TEdge *e); + bool ProcessIntersections(const cInt topY); + void BuildIntersectList(const cInt topY); + void ProcessIntersectList(); + void ProcessEdgesAtTopOfScanbeam(const cInt topY); + void BuildResult(Paths& polys); + void BuildResult2(PolyTree& polytree); + void SetHoleState(TEdge *e, OutRec *outrec); + void DisposeIntersectNodes(); + bool FixupIntersectionOrder(); + void FixupOutPolygon(OutRec &outrec); + void FixupOutPolyline(OutRec &outrec); + bool IsHole(TEdge *e); + bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl); + void FixHoleLinkage(OutRec &outrec); + void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt); + void ClearJoins(); + void ClearGhostJoins(); + void AddGhostJoin(OutPt *op, const IntPoint offPt); + bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2); + void JoinCommonEdges(); + void DoSimplePolygons(); + void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); + void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec); + void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec); +#ifdef use_xyz + void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); +#endif +}; +//------------------------------------------------------------------------------ + +class ClipperOffset +{ +public: + ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25); + ~ClipperOffset(); + void AddPath(const Path& path, JoinType joinType, EndType endType); + void AddPaths(const Paths& paths, JoinType joinType, EndType endType); + void Execute(Paths& solution, double delta); + void Execute(PolyTree& solution, double delta); + void Clear(); + double MiterLimit; + double ArcTolerance; +private: + Paths m_destPolys; + Path m_srcPoly; + Path m_destPoly; + std::vector m_normals; + double m_delta, m_sinA, m_sin, m_cos; + double m_miterLim, m_StepsPerRad; + IntPoint m_lowest; + PolyNode m_polyNodes; + + void FixOrientations(); + void DoOffset(double delta); + void OffsetPoint(int j, int& k, JoinType jointype); + void DoSquare(int j, int k); + void DoMiter(int j, int k, double r); + void DoRound(int j, int k); +}; +//------------------------------------------------------------------------------ + +class clipperException : public std::exception +{ + public: + clipperException(const char* description): m_descr(description) {} + virtual ~clipperException() throw() {} + virtual const char* what() const throw() {return m_descr.c_str();} + private: + std::string m_descr; +}; +//------------------------------------------------------------------------------ + +} //ClipperLib namespace + +#endif //clipper_hpp + + diff --git a/libs/clipper/clipper/clipper.pro b/libs/clipper/clipper/clipper.pro new file mode 100644 index 000000000..3adb128d6 --- /dev/null +++ b/libs/clipper/clipper/clipper.pro @@ -0,0 +1,30 @@ +CONFIG -= qt + +TEMPLATE = lib +DEFINES += CLIPPER_LIBRARY + +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + clipper.cpp + +HEADERS += \ + clipper.hpp \ + clipper_global.h + +# Default rules for deployment. +unix { + target.path = /usr/lib +} +!isEmpty(target.path): INSTALLS += target diff --git a/libs/clipper/clipper/clipper_global.h b/libs/clipper/clipper/clipper_global.h new file mode 100644 index 000000000..564be1f3e --- /dev/null +++ b/libs/clipper/clipper/clipper_global.h @@ -0,0 +1,18 @@ +#ifndef CLIPPER_GLOBAL_H +#define CLIPPER_GLOBAL_H + +#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# define Q_DECL_EXPORT __declspec(dllexport) +# define Q_DECL_IMPORT __declspec(dllimport) +#else +# define Q_DECL_EXPORT __attribute__((visibility("default"))) +# define Q_DECL_IMPORT __attribute__((visibility("default"))) +#endif + +#if defined(CLIPPER_LIBRARY) +# define CLIPPER_EXPORT Q_DECL_EXPORT +#else +# define CLIPPER_EXPORT Q_DECL_IMPORT +#endif + +#endif // CLIPPER_GLOBAL_H diff --git a/libs/clipper/cmake_install.cmake b/libs/clipper/cmake_install.cmake deleted file mode 100644 index b18bcbeb6..000000000 --- a/libs/clipper/cmake_install.cmake +++ /dev/null @@ -1,44 +0,0 @@ -# Install script for directory: /home/valentin/Desktop/drones/qgroundcontrol/libs/clipper - -# Set the install prefix -if(NOT DEFINED CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX "/usr/local") -endif() -string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") - -# Set the install configuration name. -if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) - if(BUILD_TYPE) - string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" - CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") - else() - set(CMAKE_INSTALL_CONFIG_NAME "RelWithDebInfo") - endif() - message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") -endif() - -# Set the component getting installed. -if(NOT CMAKE_INSTALL_COMPONENT) - if(COMPONENT) - message(STATUS "Install component: \"${COMPONENT}\"") - set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") - else() - set(CMAKE_INSTALL_COMPONENT) - endif() -endif() - -# Install shared libraries without execute permission? -if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) - set(CMAKE_INSTALL_SO_NO_EXE "1") -endif() - -# Is this installation the result of a crosscompile? -if(NOT DEFINED CMAKE_CROSSCOMPILING) - set(CMAKE_CROSSCOMPILING "FALSE") -endif() - -# Set default install directory permissions. -if(NOT DEFINED CMAKE_OBJDUMP) - set(CMAKE_OBJDUMP "/usr/bin/objdump") -endif() - diff --git a/libs/qwt/qwt_autogen/mocs_compilation.cpp b/libs/qwt/qwt_autogen/mocs_compilation.cpp new file mode 100644 index 000000000..084a1ed02 --- /dev/null +++ b/libs/qwt/qwt_autogen/mocs_compilation.cpp @@ -0,0 +1,26 @@ +// This file is autogenerated. Changes will be overwritten. +#include "EWIEGA46WW/moc_qwt_abstract_legend.cpp" +#include "EWIEGA46WW/moc_qwt_abstract_scale.cpp" +#include "EWIEGA46WW/moc_qwt_abstract_slider.cpp" +#include "EWIEGA46WW/moc_qwt_analog_clock.cpp" +#include "EWIEGA46WW/moc_qwt_compass.cpp" +#include "EWIEGA46WW/moc_qwt_counter.cpp" +#include "EWIEGA46WW/moc_qwt_dial.cpp" +#include "EWIEGA46WW/moc_qwt_dyngrid_layout.cpp" +#include "EWIEGA46WW/moc_qwt_knob.cpp" +#include "EWIEGA46WW/moc_qwt_legend.cpp" +#include "EWIEGA46WW/moc_qwt_legend_label.cpp" +#include "EWIEGA46WW/moc_qwt_magnifier.cpp" +#include "EWIEGA46WW/moc_qwt_panner.cpp" +#include "EWIEGA46WW/moc_qwt_picker.cpp" +#include "EWIEGA46WW/moc_qwt_plot.cpp" +#include "EWIEGA46WW/moc_qwt_plot_canvas.cpp" +#include "EWIEGA46WW/moc_qwt_plot_magnifier.cpp" +#include "EWIEGA46WW/moc_qwt_plot_panner.cpp" +#include "EWIEGA46WW/moc_qwt_plot_picker.cpp" +#include "EWIEGA46WW/moc_qwt_plot_zoomer.cpp" +#include "EWIEGA46WW/moc_qwt_scale_widget.cpp" +#include "EWIEGA46WW/moc_qwt_slider.cpp" +#include "EWIEGA46WW/moc_qwt_text_label.cpp" +#include "EWIEGA46WW/moc_qwt_thermo.cpp" +#include "EWIEGA46WW/moc_qwt_wheel.cpp" diff --git a/libs/shapelib/dbfadd b/libs/shapelib/dbfadd new file mode 100755 index 0000000000000000000000000000000000000000..5d0597c2c93b4bca2250bd8d411290a883637594 GIT binary patch literal 105536 zcmeFaeSB2K^*?^^W|M5PAsZAS0?G;tB=VFeG$86OByblOj1UwnN+1b>21sEevGNd1 zqS-F1L2ad$w$xgxwx3Fs;ONLpYixiz-J;p0emLoQ-;qJe5_|GGSt8|3Nan&b@8_LrB0>!+1G|BG2Se){^s%qwo4{OG^eoRikO^_w;Cy!zp-Wp&mNhxro7}YJ%=6~^+mXEx6$`IyY<-n>)Nuz-G)5-K*jojN1mS6(6?snOHEXaQ3^OjV*oiz@-^O zW-jPg{?9k-rj|7S;eus%^t*j^-rnoIFYi0}`qPpBX7)#a+&dQbX}&w$^12K?GH;BP(yo;G(n zc@~`kf9o0W=bk}tRcD|->kRaqJExQ9Axv&J%DO(+193X~pPd2!yEEXOXTYyK1DvDf4aht7I|D+(^U$gl7mW4Hzxv~US^^_r1-B>eCU7qJfQg3 zVlCj4tvYtTC8y$FZ5C^{C_b%YOvJegzY=`1*jlYyVaz0|_{d@al-1t}icf>;?|G`$ zOocB~@|>;kFCy)(WovH5-=Xl0XxDw3cJq`T8kGDXljj`O-#ji*c*;S?=OL@VN^jQq zdKI5TYSE+J^Epe=yOlosnrN+6(R&sCe1%U^^c#F8!s^#Jg>UFGzSk)}8 zSBx|f&nST$ir#yfiD&%4r$))SPRX;tL~9KSU)x2_?#dp#UGP6r^sQ=K7&GwsDezga zldLXw_=MG8r5`JX8LsH_y3lU}eRptLr|ielGZoJHyQjo#?3O!oySwzaNVThV!9QT(mHwxQG@3Tc(!a9j6AJ%x#lKdK%RQ>y zGR0@7(vMB`D@W*^n%iXxRPP;McSM> zHFb;UYBOinE}FL>IA><%+?%!P`guWZ&cfR21=^fobxn=7IJjs*W$mq6ZC!9NNEZiZ zRo+a>nR8~%tI-x!&#I|eSV^kj!YVVV(JJG}8t|E4J%4d^kY$yNYr%GLb@k2QG$)}| zkg$z8l{E_&S8Mal>Wix9FTAB1l$F6-YpZ9@o@q8zRlR5t1zC_#f6kIc^Mcjd9Eek; z%?d7@6R#CqSXWzHy-4bUQ~j)&bLK6WRWt7=Xr_9;G(f@T*P;eB!wxPA&YVAM9wc2< z&E^GNxwwus=V>Kl$Bz>!k@3|8s~3%*S6x$8Qaxt@i>{#@{sqD68><)jg26@eX4gTk znf~%gGa+~Njq?_xM)@RgSWsO)Yj#aFD@}pa->p+!H7hua#S^N7(uRLQRdqcPQ>%m0 zPU(WGE9Z=#S5rN1?yN;D@Kse!o)w&TOSRCKLudIivt=d#yNoRj8NyaU#TM#5`awu6?hknFs##@YYMy)B;l?xYDnbl^_WXDWB zlXx5kEm&PDJ-ZTi7YIP-H_l(UKn=xA68RUKEJ~_ts)N;4(CC#Yu9~-CX5C_dpg=39 z={p5HUDrW9Zedk**{mByMNpimEOE3k*gid z6FCf3T`i1bR$WcdSh(=!#Vnm-8TRbOixc!fn<$-M8@!bb2!qMf0)bQbPnxyp=2I2H z@u4uRGp!bytu_Evi#Z67(?~g`8iSz>R|Fbg&Y3P&dRiN0Bk`_{7pDPK>7qpor5$rn zOa(#=^f@qVad6VYs(EwfRaccjrg)D|V=U(QW7JXA%roa-9Pc=_AWEG|$1x$`A3JVl z!SMW|c(yZFFnnYjTR6NEU#N{f<$;g1VRvtre_Yc$|0O5n;X(nW#4%P4yPOQz!9)KZ z|Los`=KJvJq@jz~5!rDm$s&N~zSTd+8AFQJ2BC@TF>hWsMt^@-a9!_tIHs^`Zz?!= zF5x8YKMFou=xy3(fcaSGPFCF4(8t8@Q0Ge)-mCBqwVqpe3*NcVEfpc0oKu-xG;MbR z-ionVwkH8^^^N#w0-k3x)^jKUe}RQWdNcvwKLKyWvy6**j$%F01#ZbQ4pmFEz=sm> zSc2ov(FD9&y3I1xF8L@`3f_@`w_ss6Yz-#dYRO#)t-xRkC-z*~C|7CfAQxAs=VZ%Dvf zdlTZHO2BikZar-Yc(;W_x+4KUAOUYQ9&i}pa0{?_CO+2-FP;8yRpAx3Y###m5OSmWD27%up+>3Cnz`F?3G-DM4|BWzBGFB$=X2LYZ zm{;Iu2-5^(c>+I9n5GwV3rv1-Bo8~K@HkDS<*kN`$K9JSjB9dtGS1z3Ue-}QxF+TUl+a96)3;U9XZ zB=k9GqKjdLM&lNp`3X{U`BZ za0M#8NYjn}6{?7~xj`2hxf(^GcEN|<$#09!L)nWo;OO1R`NQQN2dM4>mC%4<0x4+n z(fP=AcGlHT%m2(DdhG@ywAX0-=ulaCAd>v)MQo+pVo5Gtg$f<#Tr|zC9X92STzV~l zX+|XZDx}7!qekfC;JKKhHiDR<-LCK0)7ixJTR1B_VRY?W5=KUzC2Vp}qQ237GRX)X zGTNh;8~QfmwUfbYFnq1tWSBvQ*7$Vg*Kp~7K&I7=Fd8rY19Q_TPlge`^ie?3=b^!< zfi7%Iej2dO>J3nY_T?6^g#Jl>eQXXWOnB-X*TFWJmp6R(29Q-5Vf(-wWQNPJ6TWjND7N3p3VgPKCaI;w(>;9W8vv0zD}3i}Gk11)LPe;( z{aC;DSazg`!?kHw?%$f*TFO1yk=727xQxv$Ri1Oh6K0&2s&||!e^>qyQ1%Jm*@kLH zctsi78P+isn!BRRh%EJFJwwZR!HutusaZzlRP^PFGJ%covn?h%Jg%y-O>f_mJZfCU z@;(sU)y=B!GV7BG>W8OJZ{AfmFx>baV2rZR_C7tW5r(d+j6zd$bt$lI?{!SZl&1Q(ZXO?;c?R& zqxz^ua{Zoady1;w|4{U8G!(aY@pdZ@kj*I?;rQjZje3#=QZZN+7DYfKzR+RlNSvHe zdGic^Ij-ghz~S@?a!^5aBTGWRi?_m#v*~!pUCj~J zU%8bebYE&-m4vUr;Cu{)PC1i8XC3WS=>GL;UPiycjHUErF(vo6w)#UKfyd-RP4kCh zUB)F4`UK_wHEPuiI?YqWzHP;Pa=wDO)p;w_H*q8xrCup>E2UyX6 zHn;ggTZ8rf%I$&h6Eu|VjkGV0jS*^I0}3Olu>sJe=Fhe_Zd66Vg|1E7nDMSA61wg> z0`!=Gt9d*;Veb13i*xuUQw!Ej$wW(C9q`@?0$PJ>yd^AsHddeh)lGFwi&LH z*Sy*`Bm7sh(-^SEcaj3R$FDUi?Hg_wwR73{ZB5CP7EPU*dsn{OO}^X742lK6&K983 zF&hG*lN^Tnub{>xaHl^EPsLdMs?%Da`UiY1_MWl5m>6?fWx&mDMB7jgV-{V5)TrEP z4zpAR^EKccy9P|7Ar!~`N%N8Vn(&0_qYf>tp2~^PcmTdnR<2Tb%4 z)Z9_`V=NA#anr-&X24?m0lT>U9Ih#n5=>DA35*QQ#$m?k)n0}%AS|pyAHt8p^clXu!MyKGAh4tH4OmE=v#;B z%C;M!Mphw{iIqLpaX=X5FAnGu+AKAA!Kpm0u#n6-kxg2?BGSk2Zh+s_ax$>>b#r$tP|n z%}31TtjyccF+P~Nd@|BNuomBw>wepXZ)>>h za$r!Y0Ys?ZaG7Sp&~~T4n}!wTHBO|;&*`y@=9hzMMtDMP*#2-xp9ITI$Eeo>@`bQs zyd3nl?@JDZ{`m|ydR?OJzs}5L%8GP>n?!rsDFxKez?b@&AV1~r@b|fc{ttmD|QT1m75F+ zP`sQsj;FY306eF)vpuep{?ND6rsluP{zS(>Ff54sM_KFhbzeYI*9$f0!EQCzlRf6n zS-DqBnX~e^mQt4$U3Q3OjwSA4UrPx{uz~W8dT+(cX3MgpQx!|ZK7#vaKc%(&niKv>fm{xYUf0dHrlDT%gQtQ}apMd@r3*QXm~%QK<{?m5u?&EK5{h>E8=GpNH z5&Q{AUIEF|G?YMSU%bTCwA2puMlOBibfrN*O2RAw(JA$UBT#ZE=X53KVdj^>w*%9pY4>4vG% zYx$VS*j;1vTShh5Ga}Bnd+l<_|_B)^v7W6VkZ383MrmSE_Wa2JPv4&&% zl8+jW4|g?fL7)AN+c8-?qT3+>LYS?&5``Mu+u{B?%*{k-yFauI>o_8m)t_~Ays!s7 zHn;3!St+#72yHzxYFMY0srRKrJxH4DwB!RPB-N$7~&W)T~a(T$*NzRL$*VS}C zWML%z-S!zlguX`OJ=ak&%-?Vs$5U5Z#H6q4elQ5mT!dkHCQc zw_c?F@4aZ|fGN9kZJK67V4mdKG)XUUZCaLwk27>HrxS{jLt&X-;zfMzpJ4w!$qw=q zWZU;T+V{W_M0#N1Elq9Qv!Z=Zw!RbL6F`SghnNnOqWDTov`9%afWv!q7-~vb}K!YVvVy!jX@w zsU21G+n(k{JVxP5*|Cd1n05w9D1>INUl8B-)@fu%8e1PjhyfGmtqb2~++8Ffl^W zFs5RgJ+fMDcK)_epXt{Lj}u z>@*sVjSv3Hx4jfRakR2_yPRG@fm&=129`V9?egyZ{zt9-1I}Bp5+W%17E57;5&96r zbxKe&9h(2dO*OqE-u+HX<~M-}-^+a$Bc4AHlCuTu$?B|`5x#9MY6k~Ii$7t5x79{Rn3?+MAjv%2fO^s1 zX8vL1NuC@{GZCDF(Qo&$syVg(YvwuT(T|zu&h0&9WM2g3({mbk8_Nu+4A^cnplrfs}uO@mnYcZ|Dr{+bYv_(NYY8hjm!M=X?Z?wXz7hLg!& zTJ$kWDUra|Xd!y#kCc00!Q6c?6vzU~7b)>zGrXg@Ef5KG({RYrefi~PFi^}jzfc7O z<(`xNP@6w@=l*o@ClU|%M`6iqKYcuK1=g5Jk)Q_w!Pn7E5Cl{6i3?~4hyb>JXB|5N zGimsk;*Q)1Dmu)wWkufZYFZ9fMyTDK&$LD!*Y-j*h*+azD#DeKle<=7>u9hH_f@zJ~X;Qr8PdFezP4jI~M;Lq|rQ z2SSk#)0@ZKj_3riBEbE*a@IIYMXQg0+nYDw8@<&^LVs;Tf->4XpI|Os+H~~6h)hRN z`9btO=0op*4QZe{E_qK9`P57xxQL>RL4ffTFR{oMh}}%WK~FY(K#{sIh`O5pNOa@Y zoKu3I1|T)xHXRGo0bjU>$KSa1J1f&CT~?-Y500s@H0{MPmA~;ltW5`E3$OsSVhA~Q zQ;TDB;H&+SWy$$RWKSOb;=_)POX+D`clSV1b6bhaf9Td-v2*}jKt78e+G~zs6lv@- z%*^NwsB`N6?0fmcfAygfEPt5GMedCL@EbIi;141yYm!PPD$>&VF4&X*Qwd4Chn zeTutHg^uT9zZCs7n0JvM`<>FzHuL!RP43oD;P97YYhZl{KS`IH;B1;aG)3$?kGPtD zi`dv-S>vf#`RxbLqwDUe*v`ON-}NgLlwvN-Sb2>4eO8n_`E6gs-tSUw5M6hF2?`(f zbXBb_9WQ`NrD7Ciya;m0JK8!xVn6g7j37X6PZs*M-bTSePYkl;vK`8js6H-KMtxuofnGu?ifT}MsDat)nB`q~sCU;+B ziKoKNHaMMp+nYQak@CT*MbsxkEQJtgg9MRlI@jL%{(UJ0zK+) zb%za{>xnG}Fo*8l!;ZK4D@7~!c^bgL*YNE)*QOF%hp%ONmaoO@bTtLw=t^5^yQ>~O zC)X^|ZE!0-Ts?3mvvtnx=3T*j(G=W+5nd|;huPOxW}mB>2O+qY;7BLTK7S>K&DZ!@ zN%Tv|gZ9&nklpi)8&pfOj7ah@Ts)V$HhnhMwW&uAx$_ps)sl&6?ytm#V~i(IdB_OC z4~E)|%6I)b&O#o;O7g8=|I8m*z=>t#Za1FN)q^XSog~jt6((yEy4eTzE>s zrEWy$$|urOo@nL!7!O#S<*d1+eSm$N?CUI3q_^exw<3*o(EssRIl3KgtGSJFLb#t zv^4cZY$}|n>q)`QA?9Sv2TUNG;V~jJJb75E&&DecSWupBfT(7FnL|`?)4%C|KVZ+j zu_@4}Sp!v3t2rBS>W=7JpfUFYjmMLo;@?&TosGx!bK4sCeAU=CIkY+Ek&THLlkI@x zX+H>}HiX*mXZd87??oVrQr>R|?O(XExG*`kJUtF&v27?b+k2Xg z#WuxZ_~*)ZgoukGJ+&jc#^e+nfNQM=kmFdz^}?9mN34|6+i%jRt7wykq;^?C&2oP+=!Z?1gdy0F~{{Rg$| zxZhzVo*cj*_b~6rlZ8q2+jpe(&hd=h4BCWvAphmqwZL?a2jszVYX)V?h+bw%6ECMd zG+@BYJFQz8PQ3XYBlrynUkTas|wzQgeV_rBOQ$BOQ^)=^AXXq9F4VOuOh$j`N3@kUh$MNo%5qdum z`hrKH0UZCsi{Mn#)zk;>I9ys~G(OL0Knsnl3YX3ZRL-vojhhiJtq6^)2o5PljNATE z@}$a-#2(*9ZSyz?SD~yG2;tmedvqEKCPzH~Lp~%V%p(RPTsK#d6adAd(PmLCifUC+ zFICjfEUHIQy(&7fo3#!`?NTHs5oozVnt`|29(@-CSg(QL2kM4=T!X^RT;4)*Vi4WO zd4$P-84kC&|J#=Z(#Xg^oK0y(FAvcthPEWuIyDBy5onzYMuRxjy2#%W{rq2?4vFta z;rh#scI$i537%zy?`!~siz3|j#uyXG`wVnZ`5J#&%=H1HzM|*Q5=8e(ACSX_gB8b6S30J-u+G`Cu@Z>QhkWU zb7P@E>Iq*s1G|ube!?HVvOZj-hl0%B-2f)6>)KS*-P;oEj>u>UX7pyA&6kXNYsIF< z&vnjVUucPJU@n12^M@v2|1tr)krnaX%K#IP&5PjUTNfwr_s#E8*N>Z~{iIpsPC23e7DdLU^iF1>lR zI$`>Xh%bDnip2Z!n5;MJ$ca*7n0*Znmp+M}+!YU~@8s5weTH@zPK#Fd+xTwV3^~Ry zH&S)Hi#*Nw1=oTyxK2#VS2(;eKceL5`LB2NXIyWDb$n7x4==3ZF%_?#46JQA<|Z6_ zC~mqv#8&?MMTUJ?b)qLAF;WHNt;^`AT`Ss6@075@n8uGN_@Uf`C*HYAz^9hGtnyb5S z4^l7A!+eMQqh70fI*frt9Oe#$tFRsWR^Oh&PAnf5DLpBp7r+*@*ob5_Qy=+l`;)>w zQhZ50v`~49-8=+uuR9PO{2I+PLR+5{`aR7bZyIFy!qf21rmJZRSYiqEbsmI8@8D*< z@_M|X_d)biR7T1J{0}5+_xQr4({a~+S1M}C)wHo4-3D8671TjqJYIG^Hp2s>E)|1b zhPN(v^OhAPS-2&^hP4h8bCNj=#HOb?pcXrNo#AQG(GZuPYq(0}8PIi(Z02Wp+>^q~ zFce(;Ydi=@?JNDE&v2;Nik4s>m-riBvKvWbI1B6;iaY$3J?;$X`=Z^@1OKSc>UIaf zESqx-B0<656~^2IPs5r5`MKxaq9Yvijly|j2$;V|ZKVimFsS}eX)QBeWDu~xJpG|&R+G&u z^6^QD2{_$aFmZc|r3vyxUx#bL-^mkZrY4do9hna*h!9`O5~8>tbbt8Z~&#`V~byg&W`z%zGZq@>tx*}tBLa?V7dSaHaglyKC*Q@-~^SYjA;pAdJUX-UDnkQ1=W}R4JMf)m#;=|)A@niVY z2u~T}LOJgdNg~s*jA0QqpubT&U3cA#{*#%-2QST$7;ES$XIF{`POHj2ZgpgZ{=NzY zEcFb<%LCD8u<%1^q4r?^hNYgo@pb9GhRgA?KL4^F!*)IZeFLsk%@@*A{k*%yspdb{-oRl8z@-$VVhF!r+ z)Tttl8}oO8{}LYEZIiKx4dS!msq zTa?E^^uqT>ZiTA45Y36oae=6qW>7<^`6CNELTzwL0V5Qf z6qzwnGjeg30oyYwxA?ie`!Ik~cZur-crl-T9EY-aMFO+Q&~X+F(>HPZQ59IEmU`STxY0u+^tb4~mx0C~ zEtqdn1aQO*s3M@_q#18bK(2(pXTZ|VtHU8Uy*1#a@?1@J*fCFmSx0fuk0ib*r{;~k zfMLmmh;wiBA7~eX6qCRat;L=UP|m2Oo*tq06)T!wuA9vx>!A=hFeJkR?=WUO-nw!% z^~bo@}#vZK<(lOYEC2^h3JvySYnwpHpEYbPRth_49si zF6k|BJukp`;FV&PA~dkc*K+tmsmRTg+yuNolw4(Id1o@u%pyulUSMY3$SyXsImp(V z**s*InOTIi$+w$XxY6W)o{#236AYXLo99#iV#tD5e16@>%|A68#&oI=w=AI}f!vR& z1Ec-hr054PL9*u0g6{lxEq&tsd~B6U5bk#Lc#lDyG3wuSpPGC4__<4he!twpxdMJr zC$ispbo>=OpQ_n&W>ru1keT#aAKsHt}2kN<0`X5KQZrmlK1eur*h&^@rqL@plc z#_wXd7ghhb4!<)2bh@@^$ZY=EKYwK)XW-(Y{TIz1(m&VD-x#T`8lL{0Ryz?Mf7NKW z+4%6vp|`m6hv(ucQ}Z9G`lq46d7 z#SZ+8gBy)QApT4R3DjPRrN) z&4=&DSFw`cLdh9;2Jr_DL?;JU&C&AIqe0>LXp1ls8oC0FGJ#f@RMy_eWL((Mx$fQJJ?;F&KGD{WBN8hzOnK|pj*c3nZy;?#>e<%O z(F17_+`?9*_hH&ck#0nK0_j#bRQ_g<9qZ`~q&*N>u0nbk>2pXo?nF7lr7A=@V~`eM zi(QNKA*2r@J&fS@4WvD=U5TfSfqz@rIjC3PX2e!Cdk@iLU5z->2v5t-)(jK37bgV(TaX%e8@JLS(#=B46G{8t_ zAT7t0WfRgM(ltn%aAN!sQaj$+F2ac3_YKOCK7@2F(v3(rAl-^|E7CWR?ne3%(nClO zBei3vWyeC2jkE{Sp-4SQ@y7yM3DR<;8Vn(jLkd^`A`9^!hBlPe!VvRZq<# zzAruwjQ_u3$5garv(3oN8kb4^&Bfzk}#uVFQ&>ZAM znW?!_r_a=795dc&`&k#F5@$uGW6QQzUj2vqjTOxGCTtRZi>CNcC-e($?5wsD(W$>l z5E|N0>MM1YWM+>SO%{R7K%M7MXEy6}j&(_VtjA-l10ryIs5w>*sCO9ken21rN4tGR z)n`8v`gv8Rdq%vMS9Y4M@WxLGX;t8Zs`8L`58x`g;BtVQ0bEZ-Hy!C1;N}8X&Urd5 z?%z6XeqyHA_K4U#d?%C%4>F!}&&c#PCf{LSl@zg+n^QJEC+IY&i#6a~gEbLvlTb(Q za_E9SZUgW^;KvbfWV-9pO_xczUqRW!C_^F-aeDx8ZN*Y24|yL3ZXIyFhym{@;7xzc z^_TTe5MLJen-ei}XJ=-Qles=&%QnoY#-uxJH$$i9{2vdQ-KY{k{kd4bhp@iP1@z7_ z)(Ov6x`pNV)Pg1mntQ0T)7cjcKRy@M=}8Oz5Bq8ZzpZ;aI{JehA1^*{0JjIYSBO9x z%74P?Ci>5k%nG_Qx`IS6I@T$Ara!5{rO*iSxQg@odT7a97mHBVfU5$0w(P^lP{nyp98Noh;QV#BRhGapQqu~ zswWjCop!EH;5tQq8R*~+#69vGww?S=Cz~H@Y0{&o=jSIs+Sv^7bNsi{_JEQ($GA!Z zKG9BFfIEShDG|38xT6U;^4tL2Vc@7=`VPPH5j%iCkU-1w_kfFb!5sqbqb@i*;vxl_-$~|no{yDU`=+ne z!Agc%9RL0QZVI;k-w`?I0M7b-=02(%+ckOkH zsv#T+$Roe-ikx+pl%fc^XXRs^BcEe}@oyZV$+L5TTT*L}CcnD_4EKk8uqBsA&Q_3< zUsOeE;p^35fF<`KlU)9azsY zjw#schl&0F?mPbfvUOp3wNk_!mENM#J5>5}m9AImCY5ee>02t@r_v)TO;L*KsnS6z zy-20wReH5b=cx1+mENJ!pR07eN;j!=n@ZnO={}VnQE7@Y*q)Z*cIo%`1+Cu`pD=FR zXm`%E+4vs_>f9F(A2~d4SYe$&`OEW*hvyaLnpnA%F^$hMjZ>Q%3ectv#J5@A^*>-a zmD;?Zuxa&}4<>!9nt3-Cb)__6lm9=aTlCg{B*H(HJl%5vkfslC=nq)=nTpb8PraI* zxf0FWHMZ=~cY`{k8r&=*MXS-J*ggQceK%!Ga-?1bAjy{cOUz-rJsJPmhnDQ9Kv9Yx zU#a{`(o<%jH04^!JEkI^WVVTtX@qRabO}k0ou@J`Wlsx5wziBb zD9%XzVYIVV>z2gcJ&?}-TQWOk9Xsjdp<2psnbn-LD93~BuEW`l`1NCf&Vunw1C;E* z)tHva0jJn5a~>o+IGTc`%NOj~TGqXgD2+eUlybRFeA-6ly=J}-h4M+h`!N(c?qr+Y z&tkSkvYa%IkYu@VrS%@mrmw_THu#*SrF28mJ;h3=6!U^gSWr+Y266D}e5IS^dhs;5iT-yI`KCmyy>W0J!-IjtQn9*MBAI>^YZAU@&H)=}QNvYTAI+ zDB@55dJd@aUjZ>tFW2)>uL}8dR45#;cg>Bg7erAt>s_GAUy*v#(vlv&O0{6t&r{_p zkka&aEk{k({Bl_FI!k*3f7+G54u7WB+JEvx-; zc?L~aecXq(dLsUirarOC2Q5^^U!Zun6i>6=qG^LxDEvv_$0y)_rSR#Pf;YwSU}{?i z)*|?zM-q769;eX;?NIohsQXwP&$^3QSI--$PvO^e48)-K6>)zMzkUjFXG6yn4PW#7 z`V2Gt^Le+u#G`)bcW*tT> zrvRQiY0g+=lW2drJuyF$=9B}zP#ba>iS1mvwImu`ZYv6H=lTI_L+fDJ{5b1|_5Zbc zDe+8iM5b%Qm!Rr=d@?lVhQ5O@ev+;k5yph!C;d*_h`)g$Kk4_{MhrnQKj}Y19`lEv z^sTlLJ3z}%`Xjax|G_lkC%xS^Vi1grpY#`OBfbU?e$wBzjhG7_{5a>>v?-H0``B>@H^aRamK;!J-*mo;GGwA!lOfn7V2nSlAdkrbd`ecBI^a zB-OD7-zgD%sfbh%X%Z+pzVfgyUdZ7%G8-gt%jksT8kc?{oPiO*S@<4YtGIHva@Mgm7?54|^9O?Au$u>_9JUOJ`jQReKeKZPPE z14m~c{T1XjCj&=kU;Pjzbuw^to+m(-lYyi2e4Rs+?PTES?5A@8+)f6LPPaY^K#r4v zqw@j*@|+ADo&EL6C@FR_aCCa~nE<>_298b)Hvj~VjDOgEPj+9vATfnI$Bi!v)04K) zlaTqv8laKjl30q>lSs3ey+!d6AcO@4m0}>zLH-;PP+$vrp@pQZmIRk0-;45Eh;mZ# zRVIE+q}my#I;w$^_|Z8?ABuKU9hZv?B+Yg>D{aprBeA5j+D4?rl5krhYmYt7Qd=5q z!pT_DIl;yVNMcE+-^PBGIT=ejuMqO-PR5eXNdnApwh@>tK!uaU&Z`8dax#{5PO;Gh z<~kWmI;RRy3wZ#P3sCQ5Ea{wPqyK1dGM02+BS4Fjv83}_;nwP8Eb07_0QWf=OFFL; zvNcY|lFsX;WSx_-r1J(TdDzKV(pe!T8(Y$1d zOHM*hopm<4%KsylJo^Hy2Gsa)@_WKP<8u}hX$fx%W zqsZ2G3j!^B-w-ekts7m&H{dKTs91Bb6}N=AZxEf9v}YVacpu?w2;U~~wGeEO3kuhlI_MidB+OV+U*@2RpAXdz`XlL=i*$T(anNE) zyF%)J1bA>?mN!UwjvIA7BpO5^{vk}3VHgHoL85;O+yOYZDL{Q`)_<@papHxQb2Z(T z#w86wHjU+=6`RB7JA0hCk@FGnUg{#)UK78fiOV=Z^ zyqdNWeauTnChs_XP5xwLi?2Wqk2(X^^!FXtp#LL+UQOFe`gzEVxB*|OaLxr275U0Z zlxCW31-{Get9LI?fdKZ^dzM2j`F%k>N68rHd%(fn!icdbyAYg4T#U^7%nT(422*ge zs?uum&RVQF+#ZK}&~mN+>Z8k3`lF?c?t;H!GBeq;H4_SI2*^E2 zYx3-&9`-pdgZA^r0-wjW^Vn`d8V^$Ns5Vtk%FkJ@S*`ayr9p><*0e&uQuA*h?{x5n zKJ2S^Km&z8N+`L-EOFeTE7^wpTa|{Sgd;lSutGg(65E!`Q0HqyE>QaZYbUKWVs9nT zVhGT%X#<5cA%l`6f|C!TfSEXF*s)0pp3G)>Z~81o+$>NLhIhI9Zz z@`>+7N2VP`?Ga$ zB)fUY$b?Gi4teiUp*PH`d{%V-Y48K`oU1jPII}8_e z|0K#*zGRzE`7aa7cbK2bHZ zz^d?qi6)tMjHcZSIwe<8^hy)|CWmUk2ClLxvdZo$F$;cz6`GH}b|1K!QAUbH8F^;| z{z*5f!3g$2z~;K{kaaz|hZ!}b3BOALnNfoYZzaqXQcriVb{2Fp=pM{m-6`<(gkPmR z83NxXzut)40HRroUi(`UK_evB~PxSl2O$AD!3lS<7FwUJj($FuZ3 z9KgQtOe2YuK`gpdjq_(-l8dW}shaV*G}y79wdrcAQCnP19@lP@e)0t5@F1F!M-Mpi zIORzHQ_zo~Yx*ZMtkVngzi6teLieN~*E!wFOP69v$wK2b!=fWJfGS-GRL za^dO(d@mRiZ4gX{e4y|Jg2Nn!+oY*uq5e`8U7^UA${fH#U858==eu=Qs-gz7PSO%h zxWOZAP$iUpO`M}v_;dpPFP*itqRj~fMSo8O-be)YBmmlg{#-G_sSKod`b1lr{AmHQ z`r2Q?Y|Tj&PGzWm9Y);@)m06^X0RL)4y8D<9P|V^n($J>;Z(qPN%_l!XMvG|b(}St zlko0T2G<_K5*N3oMj$~DFhlv(Qu|SsmS9Jq;5~qIC##v?*OXn`hj}f5#s1VaKrsX! zc9WvP5Pl~lrk9k9Fc7y=()&{fW3tO6yAT)3BZ)LUWt(EdNk(f}!6qdP89t8Lgt_y4 zY7Lo;^=jH;Fp+g@Ju^drNrtRNg{lhIEv@LUWATlL-mmD@MBw8@;8-FsUU85**Czml z_bPyW!R+J3|mk~`?rXHCxVrr0C z%uEF`KW9rD6_d?=b0EZM;k(h0ST?RC4Yl?M^WOa(8R!*bwXOTgc(@V5Z}p2B|$n-9h5ITKM@l%Xs@ zEME?W{{R{}t8r?h@~HmgRQ*ff`Zvof8iekNX{yYhNFWtYV(3j-u_6*5D)rXy3}KNGKMU3tBmay}QPAZp%b@%pvJYYTZ* zor%|CRS?(Lzf*3qcOai^c0|g@08@Dkd8YXb@N|A-j{889@{ z)Cj?N0bMmzpJH2G16hVpWfdYzma3E*mt|N#OO^_eWdeAcvY0g*2#YKx{50T8dwq|# zvGc)+zmBG-NYk3ClN@jQnRwGvr0Fl>O`A1_YmvzM3}q2n z%^F|EWi{cUnEM`)ZKTLn4Y=T;1mVso*y_2^+y8K~9!j2#*7M+P`N&TbAl28hZ>B7V zlDYi1uq|;WW{m+u0gL^Z@Mgjex~Kmp-vJJ_!_4V_Sok}K1G-7mO=ub*(;0k~OlJ@V zEY4uA5<`x9l2h8bUh?>(9RwqZG@XG*b@5bZz##Pl#lXSN;L$xP-Ov#U?!E>S3GVuj zK!(9xDKZ70s48Y~S8gupJQOZdt)!c*5FV#oOI}%C{0Gluk&MhAnBhU|E9CVfRmD64 z<$*9f`(IT9bSysx1Lar>cPP9*8Bw6ZFNMMQ6caj}g4qfn5i5c~yX-ouxn2~jUk)d4 z-ptj@IQ5q?G7J05_^7;$&8;#vj1QMe_0bp;GdK7_T7$}qqh2OsGx!kk%ahs8;6FpJ z$n$N8O9soG+%v*Py}-bbUgFda?Q*_{qZ`S*CDk8^%V?M~id=?N?JqkOBRPVO^?#J} z&Y#R9xBkEB%wIx*uTd=x;F~}CC=*gDL|gLcYu`arX4E=Ln!;Z2a=tdC50wh~(YPo> zrCb}ZirynzO4p4x*#zS3csy&)f@~pAg7Y(Hq*F1rn`&Kf%zx)*~sf(0@GivP(QIVxbH6#ePX9XRAo%av;n+E)ZY%ro>MRt2+pb#3uYA;NovN zD9_pXzKvd1u;6>ikGVKtIW(pJUif-dC9MAP=xaH2rX;@?Nsh)PF>B-(T9TOXO@IgS z=Rfp^?KJ-10WO&Qy=3uY>@Q`_3HCdvg%N`-T~07{DgIzWf-Y4)nH@01J_gHtzrs#m zJa|5xOF)=iGT5Mntg>@*4$h~AnR)boE~`I~M0=|kDc#oOH-IR^+EH9AWYK*fiMF$i z{gsLSKoX7ciXy;bpubF_f%XIk^N#FSIhHixsl|ZhnDMt#do5t|j{ZSu-8_=~T@sHZ_n|B|NooEpvtL?u4h*F~ z_43Cgb}ec3hULCzyvTGR)c=$;Vh`~5jKYL|6PXv7`5Q7HB7+OmGAQFfoZE|WZu#W) zs?eZ)lH$?ZlHLWaaO{hggrmU>InGC>;E1ZyO)U>}4_I~@;41hU06awlZqQCDDz)-x zxm(doK3@68Y($fCih7~gL(=NUmJivlXa=B+?C`FEy^{|~&{XHU20U0@t_)#kGK62B zbSrAg^1U9SjwI5&z3?kGpGos__w*hHm=8`V<!iZ%n=0@k)aVZFs4$~wiNZ@a zf1v=1T+|y%<|84koKW%7PgedF+GRg=K$o}6%+hZJ-du@Hgf@UbuBgwKdFobd`kLI} zH+WuS`i=SGH}+r{OusQ-{KmNu(epcw)q*5O7E=gI9I`+-h6#(`FyXC$2l3}1^&g8o z-vaiIQO(j*Y6IpuQF_EiFQs8c<8u%E03UtrVJ`1-Xm!L!zttZ`?%^9|s6qIC!hcT} zn6zI49wdJ6m~fnnz2iXqO^1G5-oyJfz(K>=;5YJuS|N;K&=RW4gzpB-E%OO^6>UFD zf1id@6CUM-7uwF+-`dtdJl<^#`hf6B+c3ZzP@da>m4*)-tUS|EGRW2qM1@IwyYHA6 zCbvovWuVX;ZA|5~q=%-eN`=2r1dKX8if9=s{z>6W<2cLF$ceu;Y@;FoR}-TR--2#j zsx-TYt88-8?@)cj`@o;?L*{j4e8?1(DJpYY&R6&8%;cuPwiFxA;m<($XB1HuM6??%tK~9 zGdCdfGBT!W@59o{rZ zq+IN0@(NLwH<(|2_~pWvmcQ1EiKpxfL7Y7Lu%!9i3H=Ys3fSNcilFag)5Mk~bG5)h zyu2h(n6HL~2G)#$E%TqWpoX&$pt?)TTK!0i|B3Mr0)&zV-ys}nk z4KDA?mzj93o>;B-XoW3me5j9~sY;k|h1Te@-~XfV7_}jOrQY_=28tRKjsg|7Bmnyo zi0)B%aowp7zA1e9v-BY!i^J0MpwRx}@jf;^o_ISmKbWr<>rwOd;sK)>!0$F4r&=AS zSk|zXreG+YZ4R_{gttBGuROyx3fM)=QU$ zK@2&PFn{$`)7H^-{l!)eI*Dl>7de46k0f?L$9z8X#$|*PE>>6$Ns%uRn3xD$oe12R z2rNznRwM%91Yq2K3Ba3>5L)8a3$Gce0oehngkda7}(!=Ned>Bi+#C z_fe76*YdR99Ljffu6f^}5={6PrGRA(d{^fh_!VGt4SZiXt{=~3jPxJqT!Cgy z0PN+Ww@2rOqpty&1^R#Ft>~?Uzo0}We4McC+Dy3AZ!VH1^dum23EeAyf${}mSz=9i z@8BHAeZxm|{{nV%1*0By9`eP)Whs-C;+<;7a07kt@ky~Dx zMvWI~pW+L1L+VuFHZb8VFpmY&ztpWIm}f(UO^RwT9LfGf%Cw|bH8-?EODuYoWXun+ zGg}$#!*Z%7AQ&46C@X z4YJ6<0JHSK3=A|qGd)Y}>27<00g*v)%MNOciOPV+#AhIq7n3NiF&i3;eTDMor!yzuzCf`b_sd_uRAHbI)DsR`s1ql&E=q);WN1m5@)~ z3tRz0HTm2H3N`s012A(bQ~Ay7-7>HL8xxh2sDj{YB~4{L|;bq^@zU5N#Cd`+P06< z_epDz)N7qGS_0g~%m>IPvx0Pp{WO~XUnLc^1PHAGK+Aw~0%$34B>?T5$EIq{V|8K# z`UmeO0py$mL{1HOoB(pp9|6q#4YPcdu~)c^Rn8evrWH-ni4oWo9EKYprEf?T>svqo z>1zQnb0M>cKJGqmTiwU(OE8v#H%dRzF@8NWPNzP+IoLpYXn}PdiKhkDJtY2irpoKO zste5+j?sq}M|Abo35M0+^(3eaWlxcyaRB}Vz?e0OgOh^l0BEQy($Yx!8g<(H8Q+bi zk#rowpAbCgf5mbrgnzH`)_P-#^nfDV)@cRQeRg1&SM_rOr#n>fe+T2K9v5l6u17Z)Y_f!S>oI%U zdAj9^d)Bj@p*!nO=5ckS%D?B*J5&k3RgUeKDIajbkDV-`EBU=hAz1p?*7q3+@zQX<9;>Z=NxK(s7@=?6p_Ua~}BP%dsh-mzK9Gal@){AD`=oqWu9X!){`?T53*W)|Z1QyEE`8%uq|s z3>eNQq+V)XI2mGb{l464E40jFW_})Ah(CR+g`io-_&+PW+*GSyD$v_`Z*cKI7~*96 zfbmlm-pw{!{g+~{?khj%v!j&| zbrumpTNi+)rax$=Df#BUN4uxq%|wV#%9EdQ=SOcx8s|LV67XFJP+PGV+x*Y;&OfDw z%bo_GvjN)~{|AMygRLmlzxAMYr&mwt3Zjm>z?l6<#;JC!xV0FSIC(8-PBMOk;vmn^ zqt+FhErNI8m=(XFc0Nh{VqFdXFVNqaY1V2S2B4J4s|>|>l*K>Em>)V*%cR~8?>LH# zmA^x~m~Ed0fk}HvmF;M7v+YLYD>uNwX4~WF5|uxPTC;5`iCLKJ>gqs?FQLv6|l1(|KdznFH|ZTZf8u^C$|(?L{8} zg6_wRm2bhi;C#hNV*)rc$WyfeCIFIxN;Si-(n|MmnFf!ofxgh!mc zXu)dwxkzCx_Ih3fu$zf-OQEjsVsowbS12&|o!F_?WJ1A{lo4nMd=*4$O?Dr|s5Kz{ zuvD$d3d2}5eS?MOt;zDAUZ@pWJi%A3e0^^ z@0{B2ER9yZ@9Dg!7E?AeC%qC*JrV=v4iUzv8OH3>S%T^qRW!JjGDiIy7>EzthN%Ge z4k%iHnoY|A_!fZ4r6{}=lIH9NCQNQ$$*i>43v3Oj5q@mWqMh|MwU8^L$zj~*U_&V* zXE9ZO)U5VKr*T3tktqVZ0)G?Zek;ZeU&qE>3}EIm7Wz@fb#XY!UhmXOmx)uZWZzAI zSyVxFBaYyhdOH{J=xxldXI32=^wP{`#;E`H1LFg?O}G?RK7^u;WbQElH z2Jlw^bKV3{{bzhNGytGm&Ce6iAHa(MYDWOTYT?S-@e0^`rFzn}uvEJUTU+W194dSs zc2B1#UHa#ZJ4$s4Moo1EzFs&2yEJP1V$gb!7M3GNTNg8tn|)QOqB7_$7X8lj1B^Lc z7ho%=u!RKB#Lw)=h`qMgYOQ4Aq)}%)1~}+xov| z^64lIJX-iGlKyfzUbNW&;8_576F_lz9Kg(}V-0mlQ>)$Cz!KFg*wrNncXDg3C{#NB zTB?~+q~m*q3t@!P5o}}~69^z3D*?=`ap_P$Z#MhlRT7%Ip+&>>>Mk!#Q{vy5;{Yl6 zap81wk8(|d1e0rSBEccFFkRxBZpx@Vrs-UAf&~1c@EBQGQjS|h;-^M>mjG(0GdDs| zIg{tTZnSR_&WqpfM2!=00sDO08~?euZtkkDahARfCuJKbkCv4oJDynT2*8jGAFEXZd(QxVm&=`~ecGhoj(UpsyYapr{2!>LJc!Ogo%uaiYq3 zRENXma1E$tKFtLBA&&j{X7-b;mlk)kPcjv);lOkqm(iq^AA3d>y{c3)L908c6F8lI zxH0VniZU$#UIOqafH|)NSW6r!_)C?~igEc`0Ou3BdLMYdf*h_Ydj0G%mi_}vI{hd^ z{aEC$#2p7svK2rVfCmYnpO_T20iYk9lmlqE4ZxpRPC3h|z8%PIC{-Q(Z7w|m69Nr| zY8*U4GUzphw+W!mzM&oN=!aIPOLul!16R}dF_&;vUmJm6p)o-dVQ>X*8@Cby?nBYn zAfWm&0B;d+9KdNEXlFWO_NUAh(oDwtsAcu@C|C`OMZ3zq6!_i8w7tOZ1HtT{Gy6g` zAUgk7I7^*>7_>|0|2E@S5Lp%7NmorK2E2=*6Ii<*^y_ImFi^Liwg&^@^|W0Ws9sOo zhj>A^ik=|sou(PEUQrj`)T3I`TmCP>Aobq=+)rSRdj}X3KeC+l0CT*9u)3RV%D~ni zGoGH<9A~`R%)>Yg&+5k;Orr-a`eg}iz0+muUtbBe^qZ0|L#=uS^&aUz8yKbk3FaXE zlR>Lv*_ib_QPNK@{ncLvfL;UKM*zJT_#}Y& zpJEPv4Uon#EJbJ#M=f<2=@$X3=$*%tOkH5f|0U$Fe*;B$4y3w9iHbSIkVUc%Ra0HV zj02#qv4#NZ8n+TaUE?(ZsB6sXgi&X)4F0W^uTenOVERQ;k9eWo&y#DkN`UGL+(rY| zdfM|u(9j+zW~L2v%T$QZ0E3_nbkFrPJ_8Jb8jk}jUKq-x&kN z>Oi?d$ANN%jsxWi9S6!4Iu4X8bQ~yG=r~ZW(0QO-q4PkwLg#^Uh0X)z3Y`ba6*>=; zD-5YK=;D|8+xS2!Y&K;`v;a)qPSL2vp% zxkBfGa)r(VOoVev*il; zY`MY%P1GWEwp`&s0`=K)g?F?A)@REVezgf`I$LfAaQYay0o11Sa<c6h0<_QPI9sk*&Xy}aBk%}{)Y)>yqtpS#`fR!4 z(E&P?O`k1Se5T6iv*n7<3ed@H`fR!4F#$S}O`k1STpFO0*!0G9kby7&ORV-Kv_;j*Y5bKF*JHF_nk=EIA zmjR{DmMfkZm(S8>VXD6gnC@1NR-^ zu`HpnnA?gG)@P`90`4OaGf+|JIB%9E4)*R%=+|G2XktwC^)zUz9u|-shdo_9;0(<;X(s6*AA;m1v ztggUq&yf*h6ag9W6Bscj$5ahUuzst;7<(BJ-Aqz8d!*2TzM~FNJ#VIVFGxU2jH&26 z-co)y!x(#nq|hCKQRR`+WJ&o9NtsVl>X?dtF=k7dOj34J@RfU{+-*tOO;Wayl%-6y zJx@v@N$Daf)49Avy9KRz23lFysEefB3n`;6re;<2uT%C;#ZFZjo5c3yMJ(f5TL)SN zZ4gGgAi;j|*x|&|Ng7L;+HMJYh4XB@HraVCB(8_VQCltQ8!5ZP${weza(5>gSC~Q- zC$PX9dQ-0h0^2}i_mQ9`vZBOeMH3d+WJMEMu>gX#6^eQ*Wt9~wdxWyeiYBt+x5$ou z5$qnJvGD_8)VRyB2NVRbfq*}Q@FoI&2jD3HV}@60=kNc>3K(PQJgz`JX*HP3_TwWE zI7+?ERZkJ!CylIn{H3xBksVXWOyBUR!fQ5fLukK|G^kKzCep5RzmX)#m~;=+21f>_ z0yam1ck)FVaXk=|b9Ui5Y71HuPX03C&j^eKJw^mtb@UQ|nDL%pe0Rqpv9kS_D^turk9GEb0Xg_n{sDUNe_6m+S`t@6YENpZX z)tx>#po&j3%z+p8o7=BqDC%I-7BC3!6%K*~D(*AUprq&mm4pb5L3OqkP*^c^;mCO- zF~kiGm;?LuBbfnE_Zwg-xDe$1ISX>i4iNS5Ngz-$lsE>Bh5TtKEEx(`5;>T4zzVHn z$XL{7DDy%TZvKV_l+HquFnoAm(nu}rv_fU<>4c%85vM!oM%u<;*heM=tJ$(q1%U{w(; zBa~3-xHAJY6nlNY2IV>&6+AMyf)h9*!AIGNwwowB$QOR(C9;o2t3!p4#TGC_@t8a9AP_EqY+UQ@HG&FfLC2?ngslG0IEe6vytK8KcDQvCfsZ#;Q~kfV9|wk4Jf29D#K7k{agHYv0VW?xbKJigL%4k zSjcF7U$|r>S+>CDtQe|&zA)d-8dk-YzTCDpZ+NO;d_T{?wSxV|L(@u2zao_prP8J{j8$$L(!83j zfgJ47z~x3&8IN+-AX!aKMe$YBkBf-2R$;*rc18*I!H7sl-dYV}KbvT2Xs)+~vv)9( z>OmDVt%@#4+>keH^`nujF%JbdZnP2DMzJ$AT>t-Zjv8nL#~pFLLH1i z;BNy5;5&d3$-oDH2k;3R<&<$3PHRtg#-?qF;$Wq0M`GHNSmv^9GBvFwolL|s(=KmI zCv%CG=42w9PR6IjJDM`nGVRe+3=kgDXVTL;63y{kOKe)#g>xcvW>1ZGBywF-+Y-5H zO&!^cCIRiVw&rFp$pyllCkn5!Hnm1uTFP*W6P}i2TfjfHHJ*%S%i2*3!gM5OT5wCO z6)@K9*=?yR8mQKezG9r`e)Y=h8v87X!&TGnb#IsX7 z5)0r>T*X28H#p`~_-VA+_fTls-1%m4>ysCEZainv!$zCD#;~X7e%RE>LXz1eTC+0}aIhLt^cgr-eh`6PYaVs@>ljGNn6 zRLu`HgyR3%5ZXkI+b7%S!1~a7^SxZ{*~9Zgm#$Q=G|rXD>Fxi zcANKhA2NStwC2{CBSJ&W<-sWd^Z6@Qm|rWX4^A20jQG1PmxZ9;_dRNkS+VdUAikJ` z7NDN&8)~hBrfYMg>92iZuga}J?t{K$!&NzgclQfk6flpX=H`!#*5K@6!SbQ)kaK75 z6_oz6?>q%l%)i?An0XlX{M={-?%gbvf4grz;Gg7L0e_)iy;%%3=FQ#DouS;iqL0~? zHT&&;%zSj~3iC&yqisN&hv_RcW`lXcXf^NXhPmi}=JN(Dcy-6Ak;Hk8xh1sMEID;z z>3{yu{JHx&LW!%O=386Ij1!^yZ<*UxT)i#c-kvr`?KZ#D{haxvQD$b2y;X6|gJ0jW zAUJ;L+=2r0*=?$;-q0ts!W@$|R~$9tp;r{;aiewk{B<+T;?O)ZH_z->zo9a;%S>m@ z!BAReMqAC{t-*1p{n?x!%D&NXL&JeaXy3PmwEwYqw}STr{!{Vp(Ab7dl0*LYzHrVO{M(H}^T|wz28r+X-+liE^K-e-?i-umF~8ou+kDA* zZtmgGf&_wcWls;qXQ=0@m7$eatz58t%ly!S91PwY+F}mb`{vNLwl;J0b7ucTW;Sc~ zFEg|CX8--l$%p!co=`w&Z=cXU^SS^$_xGL8nZ;Qc`d>Sg5B8fFo{*s$95CzKzCLY! z=pTo38*Zc_?cp7}f&RW3+O0A~^CNTrt8?dr<<=b(Uay<26k50Lpn!SZL==MZJ3FY+ ze`W^H4m>}1etgf>CpMYe>U*{~%$*;)febQ-X5046pKAWfs0aDMD?;_aJxla2UbL{m zL5_Af^=N~6ZTAZEFGlO7=4ZQG&3BE~<=0#kx*=Dwa$4o3^V`kh=PJ|Rh@fw5KMYge zyMm(n(*?%>zjFn-_tOQfZLe;qXaM3T3i0g%6`EI21@136)Nb~B?!|lH)_Ze%9)wj_ zb-!XBH%{fuMd(;(2AAWmx*)KJzUI@{RG56n4pQ=z89HT_gof-fpE2rHy*?2dg3?#6 z*p1Sj0_tw2`L`>A71ZsnDWDGXH>LH~f>W4CRyNGd;cxxLTTstdgxG^~SI+zZf`Vq# zp`V7PFW+pwG+@7ZG`-*KsyDy0Gc@nT=6BXVZ$2Bqurc)Wlg!(%goSSgpZm&|8yfcQ zd-%ci4?g(N{4wSy_FlKe?1F7wp{#k^mG$OfGqgX{`j-gwKertw2F!a352*|_>7l~< zp3hI4ADmD^?M~y;H@8y-o-W+4V4``pFtq!@x$`?iE8CF(-LswA__u{ z^B$br5XyaO&vlUe>uod!9PG1VAu=y*qv*J+5Bzc9s;kW66=vTRW_sS9J%Qg&I_2vzM5Dkal?7}cge0@R~8Wdpuq9}BX zpo8>vxdk;4WL_RRO6fQ0>s35mBHY)}lu-DaqTt-XqX&{3KEJRbbnT4~UcLT)^Ua-z zoiRtvIfpP@kr|(2o^KOR(Ap_q(W1d{6|Jd~@fa;Rn8H9u6K__0WcC zm=#wYm|rntCBzIh`=1(W&Oe0_v>xMP7HQUe+Nj^~eC$=T->ISV&3?!5HSpL_SQqGn z(R}<-b5B4I(S3IJF}EGUBvLDtU6>)FEiJ}u8Awmsuh%}eGX(#WYs|Ri+=mf(}HsXE7!F(nEj6qtyu9^<;Cj( zBC52x15RPEL|<0(gfb#)_C5NN`ABYs`QyIY1{x2Q31+{e=EfD~*=6R&z4VQ6HqBib zHSZ00rRQKpgSq)==nZp1Xr9z@-Rc{2=Jt8BK|9;*+ZtME9>g5>Qc2e zc^(GG9T#qSsKIy^8-U?)G4o*^=Sy5ZJv1wl75;d!~cB%jcY$m zlUD^k1^DQI-E$k(gD2Q0v=?z`{vfS9|GfdHfPX#o-#N7XY17uRRC7SRnJhyez4(+i2dC`Y>NDs zaSS6ync05@O|*!~2hyj^rw4?FymeJW1OE0b-_tO6Pvg0Fkig*FVU)a1Ut#)E9bEb1 zBFe7hp89?geUcF7E=(t%>Y1zi%aeqHTJQ~` z3C=u?lI8UEDt)PniS%ca7{Li^-d$4v)mP0p#%wGackj7z-@bhhVd6Zr66qri=Amwk zkHd~(@(a~d6;FXFKpp7`+{QdMFgP=C_{Tjf*R8w+y`bR>nEC24=}y~ZZqKe{kKsV}VGwf-q3n#Q>R{xLN**|iT+bOid;_X!OP zjh#FH#h*aVsRRNxV190JJ)FJ*h*uIA20<4z|9xfq0gEx2FlF4v((tX z>wBtV-Il5A=Fgo!7i145XexXGG9F#eL+~Dqj=R_2e=SPi?4-W-dP(rYfcdhqe|=BI z{D&{vu*y6W6Y=F(P7Z2Cvceoh3zN4xF>0A($R=g#Uk8U;382sjQfLORqOVWT7cDx1 zW^E|@+N!2Ts zBKlr}+;Hs>8d$%i7+xM6$~II~tUpgxaks)97!n#Hv&=PnK>AiEjYve`XWM6o##!=8fdNjPqI`3|<%9f)NW zl}mB=>DYn57S6}JmnA~a{s-N|%0p1|MFUe^G2Nj(9-uk>iJh3G`<`0aP%&*X6*xaM z*MGZPt=){!(V;zu)%A_ThgH-4>l;DS^nOhwn#(5JVu@*;$>vO?IoX-&h)1&>N$e4% zQpUe7-neviUFqT}Q)bLAy`b#;vgxH$JF~e&Y(7-Q(jCpnM$^sh^RWRnb*JQtWTF8PP1>l8t2Au~*TQ15~jl5>GZ? z7Ri#^u|cFTD2c=pEk;vaswJ9@wHTR>wnSUBQx$GacVuI#IMN!Awq=ZjrfP^q)3w-C ziOskOV@m`kUKUGZKkQ%LZDS`R09nJ5=r*IJbxAVU6ptY070|Mxr8-)dHGUCzr>fsJIbHB{SrMWG<_! znTc-EwG<&*uPsFF&lw%8I1cBQs;^vvycKIH?MP%{PeLhL5^L`0jK-nC-qF#nMl0n~ zk)~)SX4EcPo=je*Y0%JVBcX*?#u9DWb|XR^GLbZvg>`+5gf^XvYZom;IZ9EvSQ~1T z>DV4ayHXRUQAe#Knr>^RYIY=yNFvsih0-;xt(jQX(1vD=NTjvXHk=FLgiB-Wusur-brhndA}X(%N=bm36^Yg)l%=o(mTiqRw_j!?)+N)Isa9Z5k&CeX+o9se zDkP?8%M6{&)X6NJ%+|^IMr2Diir|YRwaehlEpT{cvaO>z8n-J=eW#TIbZs=Aiy5l7 zsc=Z-M=Q)-9!<2M)c~!*-l7sgqh}-)&!K1O_Rmn9bC@=%fL@wtS<_0*y|_J^CT28_ zs-ddA8a-yr_-DqB-i8Y`IH+!h)~<@Sp^=mE7O6iq23ZRq=-y#i!QV`VMKUtR=vJoI z#W<8rwiwN+c%*qt25k@_X^2zq>4FEeE5Qq&v2tL!fV?@rZbFJc<5>=pdPT7(I*%DLZSVt{w){_x6F^qDtv=W#xTGO!@C>4!+q*)!?>U2v*q9xX4 z=;&F7VcSS?aN7N{GuGLh+GZe<$$-QqxmIN|Oyw~ShDNfR3@V> zOq)vR*avn|i*^82loZr1s*PoHsU@-2XfB@BLtdVzc+5!w$)jc}v96;9VUahyQw<{( zwW(a9nW95k9f^=DNl_-1FcKh9bx5#CHDY2EAnU2Wp(Ow%R+ovi#4=eUo7A3zLodN_ zFKv&VdS+Oii^r)$N1L38nRdfj|0%j;uWcdRT`Mon`v@gYjwd^({wJO%BoTU90 z*AYSWo*A_QVI_o0 z7;51X{xs1+zwSq1)^@20gJ(=h}i`Wpn&$Y%?+#)*oIL8T`?EE0H_=g~k7_R6?Kjyj88h0&lzErzg9 zZdMcBs=F(EtojVpQCrr!mc5znwK_tfuPGi)TxPVUD7aGGF|~_%sKkvzhmqO73W2Dm z{fgSWabGL6eU1uq*HUXPSfB#LvKCfi&`;~?Q9V~hQ&x4gN~$oXz1UVYKdEP}m@Aen zO{bG-ET=FW{V(n%9JjMr;5t@^(16h_cA1fmsWF4{%5c(GkheS~-CrZ8AF9yRBR4Hic@d8jivz3#pyP z*7g|gsA!^(wy0t?R~cBa!(t*=t44V~UqP=#;0hRZ0)E0m)e3kOqf8?c?2*iHeiOgI zzzg*~k{iuf2o$h7k5FBB6pjrk_wM|G^_4Ni*?6|=_U{|LJYrDevl ztUku6r|5le_cfi%FXgnaVIHg2MD%;8yi5GpVbi|R8|{hnH0yw=Iz>zh7@sbvMgebO zl#XY~t;26i=?WN)0@lwGRIPx!EmWg`Pg|&30r3W&x*$uydPZrby4e1f3Y1tC2n#s8 zOk}MU@KFo3Nx*rII)!^Am$oXuRzRt)?nIKi$0ii;i!-!dO(?m07>hs`aJ}WYO#;eM zwVGFQ;tKEz==4h169VFuQI=P#1(X_+hH9(6byhX11(Ze)8e0v4om#6uhSnNCtu;Pc zYecJ4L(Rv~P%j#8;Hpx+>U$(7wG9}x0*a=9Q7@oW&ouDQ;3XsNt_8Z=TVtik7g~*5 z+r;2$R^!$RC|v<+KGQ83=?t(?Kjh*9q5q`8?id9XW;(@ z7o9sz*OwFt9A_LljDS~KsA>Vl4b&w${$H{B!CGlZ>A;|RhTHZ9PD93y7mS+DSC}?(}KqH+M=iujcBI zNP%U5EHZZN3iN?L+$R2nb^eM|tnSWW_ly=d8C4Q%T{cQUF$qRr-+e2Wf5oN~@No-O zBj9mHfpu@U+b~(3JYkK0RRY?h)+QOX?CEEdchuS>=8LTXW0Q1QaUM`^3!Y-lCu|D@ zv@M8uEr@t6hl*ccUJ`{+LS#(J*#XflVLeh{%DmMpuhU+F#pb72RzJ)$S!3M3cX##~*CR-gIsk=mO&>1qO_q=kwi*guPD}K# z@PPOePSNoMlwb)M8zo|;O@VR?k}3I@wjcpT5SsOv-`H`?)7A+dCDYbuSuJ43LV50i z-CSsc&veTyf{EdBV>FKFfm_|O+=M%X&|OJUE_1_Rt-%=^AH`y#>v+~`C%IBVYjpBd z&P}46=~i|z^Ve`%Y^0^93Q8K|W0)?|gvHl%H&H+1N(1-T+R<+NB#vZ&?(b|Nk5_uQ z7BWB&arQ^<)NT!Ko)0z0O+3tL4g$u%5-;*J`WsGz#>F1fg~pzh!){BxBy!4=MJcxl z7g-bcM)&QHPfx5mM+>-`Q*0#&IC+XL0+)by@Wun(g4Fd$?hs?aE8vqB%G38nBmL_% zy0Ewr@J8lBxZct&8PP&I!7Ahou``< zfg2cy;rki}4_IU~dJ?Rvhf`ub%DR5YDd7Yb`-8>|PdpT|4DmYg3H$+CP^P#g?Vd%ML}u}dM{!oJEvzQrks?)EtGI2WFu-O*&mwU0gSw~%89c`lMM4)B?#zQV>m$Y}{yS2M?V8{=e>?U9nlt!h-;p3#s9d4x%ZDj`^)h!D&kJyK}P z@r<7$=U$eBTQ2J+aVzf9d!)dY;Td4d>9_W{c5(_|320cM7ZGqQqx4WIx%oDsfS2SE zY8CdkD2-c6!vdZ+S(9OW7Esjau~KrP34{VVm3lWKZ)atbEDf6kl`AANag|-?>mfqjX4%tHq;9Etq!p^NOVaZXl@YrE=zx{fZ{5j znW2jvB{A#>=WDqLgRR8SbUSd}CS}>$J2)L|biV>`T`Bic=a2VzOjxdFmi|};>NQ#p z{aLU#*`=j+sbEDN)(^c|B!VD*vn@cdU$n(Llnd4t?->Y=OwbCS<`kY2@N~;_wE~W0 zlpYA&rg~+CMV6D%+ef{O)xtQ!GGeWOPFdbZ0B>+biY!LYKuo82(nV)?(uFz;_zeqH zE8xA1@~^X3R#;>?8GY(JUMr{bbLoN+0)E0WqEWzPo)MDUVH0X0_V*DM`?4iIETC}d zfz@Ww&>xtgkY!V+6u8RLSL`cU402b6eHB9#w84A65U&{O?$*JZp3zdD~XC%hOhFA|F-b zIA#}eigy^=IpREnm7CV*X6*=v@Asq=8g&Bx)I!w?_%x$*=abyeZ9)O*9Dceqq2&J4 zBJ|GTTqMfTM+6jZ-6bVw%knHYj*QjHU*r_il7RBx4)7RDz?pfbN^Y)gs(_bUs9FIt zdAyQ4WD{yb>~F7WVKGfK>uO3)l*1naiW*HQxm}jhuz;UsRM6PhD6rV3nQg-~Rxj$X#FAEUR9UdC!aMsFR3aiL{ujet&5y>&F0VW`DeC*a5rt)rJQ z?8oS>qnEMTkI`F4FJsi*fewt(m}fY}oG4(bR2R{EGYnqAsU9^Xx5px^6R^iZ)e3l5 z9pIl2z?vakW@{z~&WD%+|b;6U#9*2q*^o%!y*{ajTtc1njajHVWvpw#LWW z8nN~cn^!=wkF2ffk(_Os=WgW>Y|>virRiGWftLI#0Z+G3)rRX@!$oUtl4luw(L#A1 zz0BgG?H0*KiGWval;OHwU~6Bu99k<*xyj=4%=&H%i}5l;FAqJ1be$#5<2fOb`VKd? zVCz0Zud~T6D7`x6vfPl`J;9Pc#0VjMl1Y7^77LNc`wxrmys7}DXjPiG}moeI8gYlx`C|E)nq8jM8l(xqHvF2nD>~Le&ZQDa#1YC@4m}&BkE* z7w{Xbk)DDHEP8cck=#2DN`b{3O)0q{YzfH}cs}DarR1)0Pzo&d(3I{jE>#gHVqg$Z z)DvTMkL1KXAQaH4!P}@_4K<=+?itz~(ooYQIdL0Sf#R#Pt>&rq+EF8R{E(^e)bRS9 zPjhCO)r_?Qu42@1dadaL{c6((m=n*N957BB+LPg8aiF&Dqa9Z-)v_zFNkFLx$*S*> z-1yNFh?@kI>S;pBNe%HE2La{Z@?!U1K#2m)D>t+{}B_}J#OO)?n&!8{dg~!i;WV7K2K!a9Ss}Ex76rH^#rAx z7R$n2y%KeC4=ynF9og9hZPT@HL4_WcxyY=W{4Er&9*Eyo`YnH}p0i7DXQ=%}6nt)Lw zpp((N6Xa#A_ha;q>B4vyo9f#{so~nE2RMZX1sr#pF2W=tV045=(QH%KBe{DS3qk>d zyh_r9?q>5U4U5tjETtPo{I@Le8~=yFzuTyfmR&8f-#=X{R4bt9AUmtA3fbao1$0)( z+qf%Oa<`?SO2E06sh%02iR-$gu8w8>sks7i`%AzGb0m{?6bat_uB%aSIkKZfRd+y5BRMX%v58g@**BLO#M){*+UNe33KK z1bC7vpahhnbE}np_LAjkt4E1abTYRnpxlDqX8{EqkiIX~Npn1A`NtziNTiui5dm$k zwQlVaLse`Arq*n4Pl?^MK9vy?i9;A6pu`~pLO@aKGe6$S_B>+SwYxXF+_XM+c}YAG zFJYat+96cs2{t#8&l15);#ma_$?30S}=J?Tjn=ZNg7z;uHpUNYY+|VJGL;>F&>XfKq`&+Cl93YJ0&og+! zvaZo9zOjroHCY-xeNJTGY{{+`ux5~`+bCcQqx1?ua@UtwgaV3FG@<0gFW4FpaEoQy zMgg79@U9-hTx0r|j&xys6L6JfaIJvV7OGCH{gTyAwF2I5q3Xmg@g{;r8fk)MYOOf- zavSBg-Y3eWv3_ZrE}%FV>KPY5~PiEM)KRc8eB1 zA^KRNtK3o~rtjeZrISo%jo*Stn}U&OM#&CcA{dEpo5vmIc8OcBgzUGikoELtA(2qV z3?ZP+>yb0eqNnD8!&-9$di zSuaVguBiR}C06l}?Sfuc{BBww7kEiLO(k9Q)7)#}^iQ%`o-X00_0i}h@n{Tj*POyB z+QoK&h6=c7j73r{pm5=(!)F4$@%3lEkg+9jQy}!g89jm#c5G+$#%z;#nny;#YM!Ry ztSfqRmYdecSzZ#4v#w`N_u3k7>`kMa)_?4CQ~3-&!J*nWLpc2qlKvKnrx9h0d5uZ@ zek|;!@maE^`e|dn$SL})fS0_iETi;|f#kkp6S`YnWZh+nul+Jp-`zWxNO_O} z7$x8mj!INTzzCzXQNkY<8=a#F||c#EdeiKlx{7_ecvV&@K_$9R9jN7(y&))qo2}nk0{+{ zDQy(+Y6}$>@J0*OD4^3cZ}k4y>kkosjU}sADk7!T8s!yV z>lI%s;zgFvxcC~^PF#zC5J79K+O72p@+`ZAE6H34;0xI+o&a{!`UbF@C}6A;=SnJO zeaF_>)mx`=)B5Uk6Zz;o!MgA>8+BpK7O>kw)e3kQqjdL>9R3qB^VSMDhf$hPa-Z&F z5em4UQJPS4Ke7o0d_Ip*%dx+`)d)*9oQ&Sc^D(pws9x@CX$gKXlX zmZ_c?S## zTA`2Ybyqr-&&?=x6OVkz>#jm-yJ6!;NjuZ%<~Mj}j>n_dv)k==Z~ctPakE^*=|E$f zF(mYl(}qpeuR96;3tWCW-iksUPpVgXorFSgGZT&!cX&zNRS+9)XI2b@YkM08-Lyet ziO0c0a~sRUa3i3o@Cg(tdfejj#FCo?%Y4JT#o?y%x&3g*ZGo}nu`50G5UQ;l@gFE%&`JiSg1My zS1?MC-jb`e2?hMFg{l?s{ybiH;CW38i)o^Ul!kjG*KTPD3%H$8^ahr|POaYAz^k>| zPiwW0)@rZTeJy@ky~Dg$YmJ}Q8Xv7SK3d!Tw0d7j8P480%kt9n9)Zg&XI2S#fraus z?lQS(kVR4}CfsDB+%5bV7ya2HsT1(FkQICaeuYsw(j@n9Hlcvu$|IEAs$xr`fOU*2 zFjB{M_DC*m6AE~Rh4R$gTZgdJLAZ64O3s!Q{%C(xi>w~2nvDXAKoVcwBRN~VXHN8* zS|j3xn`G7a$l^7qZSV)&WYP?}j^b;lIBypd-rKD@trf=AmZR5to5Qn07eV3?%o_qa z?W*n(@l}@iMgc{Q_M+sZ0zNa5D3!3p@F<{DX`Q81q78%sike;n&vvwi`m(DIS}xlt zb*i!Iv{A&`)_WEtl`LQbrynx;xJifOI3L#n%J26=ZZ>R4-pzOHcCEzt?_2e$60na| zA5Q>3!_@z2a|vj3g#|pfcR^CLz#{Riad&ai?=6x#0fT*YMJQzIdL%cNv2^?7x`A}=myiUNV zh1w`!6Qgvny6rlhOGjFao*_!q35j|YQ8JAdpJyj;F&8c46i!6lpy#F4)loZlD-T{u2;;lv)ni>hJ>;v%;wW0=Ma;}qkkfU7LjS^=vVrJW|Z zI-9UJ@sll*uz+hURHJ|*ki>_3Bxj5F+;o=kJ8R>u*W2m@+-RZJ3b>h3+Iq>wY(ls7 zBK|^)BrIUWLNy8~0=4y$v&DO?KY5l`_#UV5y?}pZls46EmzOc@$LJjny^Pg%`o?Qlji0Or`cpR9TxS@oVeGU8L5!uJB+W}#{Xyq!`0k(1)mti@O-VD3X1H*;x=%_v~(Lm6e< zl%|9A0?Lxe-_&vzyTsNg;L;D(IGsx`v>62~|0fy4evIC3<<(g2$LQ@=rEJf5PT?E@ zCw!=>UdFH=qt{d~W3?aS$1%0WkI}pODdCC?;}mria5$s<1Hj7|_G9$c(aTuv$LOu2 zm$Al=@#EC-UuOK5P5qah^D&!)+e)5);QiXV0><&KFpB(sCFW%e`!RakaXQbj@;?tn zkfaZ~o}}*LM`?TIk(v;4+8ez*c6E^(?uVkwS*}};JPz%R{|x5)XZe?~Uw_5vE1d4) z-D0=CHC+A)PGzrOo>P31@v;f;<`+JBh9-2f>+h!TWIIxvW;pH5z5`r-7pGt6RQA{1 z^4;5-yLi`2_B7q}vNv=qZ&2LNX(iw0)^pm$sheN!$PaS)S2=x}(-%0EJ8?I^+!4tg zjNJdoZHt@U{gTfC*Bd@=`aAj6#>1S-`;7APqMLpszpgivQ+f4JUMh6cZ(zD8r|vfc z-SoqGyd1^p1Wx5uH8;Jy1$&(7UgT8XignWu8muwHICa0E>ZX5ph{pVlQ}+vFZu-g>utxew*#)UpiW2*vYL=l;pFn_o`3IKlMt(`fmHyqkVF-@}aN^lVP$ARafp z`&3_*+*dE~Y2b?~^ zsrz_qH@}>2FGtx=K1Wl?IreV)442FQ#<=@DO(FjU!%bf_Rb%A8?UYZ~`L&$7>AzN{ zF+z8Q>Exflwa?Jy2RM~~qa^on{I^;Ddz=oRrYWX#D*u*E^t<(al>FE% zEib`omQ%6MZO^?QQ4cr$LY8+ar>i*?Ke*{XB5z{JcOfsioTR1^G{U}k>|guh3yfQQ z@r6cvfm5=EO{0%d#Z#WM)HI5WwLH}4<3q-Xp-zm*DK@%%@qLYUS?4?0OziNL@{s93 zpKCBd#isW&BAO zem3Lfh#+LuwF2J(V}vo8{Vb388Wi5!zPo@Yy}Mj4{fwgb#>v-#_p|@8Uhq!>PxAM& ze0jJ0MaG}xCgYWb@!yOu;U+8M3cSboQf{&f8BgUTe=|2(kqJUvrNEQ_AFI`Q-Vis= zW%|@OjekKW#yrMX@l^RB@^r0Ye8~izKd2LVH{znJYg+6(WBkcA8o_Qe zcJ?Cw2BzP9zNSCQ^E~}-V2I(J2k-7h&O&S){4CyBf=Sp>F_wFlr|2C77YEc9B!A^W$`4>}332ZWkJV>7qAt zsojsTURfsI#rRUDmzBpiMLv&LF)haUp2Bm+kv!WA{+o!q63pY%UE}0$MLxGL-|-vA z+5fxF(8492-(&h+u6mVVi;e0f|A}4NaRlQ_-Epq)4#OEdpXm=UeS+~7j8D1b)b=8$ z9eAp*dtS(j9PXz#z%O*|X1uJQ7c>64UgRHS`V#I(GA@0$7y9E&U(W5`q176{5jn1U z{f_a*Bu%)C?fI+VSudJHT|;1iUz|@+_<_dDOElefj7N0MVSKqu@4{Z>RQH09^@67@ z)KaA>|Le<&exPBv^xnz%Di{7R<99LsOcwVY#-Ct+2Dx586gfO@NdI~XcHCpgI@9;9+n8^48++Qj+xp9%gbH06!RU zEB7_Xs;iadOlLoo2v18>YqX`Mtl4Nz#UssIG94{Ob2^*J=2}~UY>A~~Z5^3xEFH;q zMw;WvL@Z-OA}z^CTRhnmjYnFt$#f} zZi~bc+4MG}H687YMOt#5o!h|T$VEVz%_HqhHfJKFr6V5Ab|e#J&8d_D^OLCi+NEto9<}J zWn-Fbrm?toU3l^GvKbe7NeBZSEfxdqTXe>QM&MvPl&EvpgYTVl#LVfdbW6OSeG z)qzsUtW36bG)LpMYtSOuX!B*%9Ff*&N8DzcO}0=C!#Q+T$|wmI>ynOitT`LsX4EcP zVz-k-@#17Iku^GFotaqHmdUM3QkNuiaJ40ktZvSvdNEs@z`>@%HPRXF@DfA2?xk8i zYMK{-q#peNj;C59=1FO1%46SRw01VORJFz$3>oO4t=U-I;T$cgtuvX>lF;*1ySqr> zw2F+jXh}?sc;u42z@0JMh*YeBl$MS}B$tV`a7?&cl^es;fWV{Hi<2#}s%V?;DlIK4 z7@VDx1_h(j#~rP$G~RhUAk9dFk;FkQ#=AtD-D1#8&Qa~JLc?gy#A1$KO-`y^gmBKK z&}pN&cy@U*d0B=SYE+Lj;Ag)UYRY7|fuKY6%cY&E>^4-OBY|4=HiCdy*+Cz4Q7_no-x;k7vp>-=w zLizld*m|p;8nI-K%^R=CaH}cQ1V%nynocLvR2Ln3Iwp`sgH%Q{*;UDwj@FJ?%M#QR zPHpar(hwevcWif=B(-<(esyvNnb_A^1hnfWKw8yPX`G4SUR2W0IEwZ!pJbn zGTS<{(I%uAQB~S55N42AI%Sk4l9+xMT~aYM8*SrUTOwE1l{;vI>Y!0?iQw5VZvmL!Y0e?6t`P`X9HHix?8`H7@*Kgq?4R$xlc#s^DYi(j6z zNLq?A=Oy>Qf}`cIlV6_4NIG5!Id${X?a7}%_#i3v%X1q^Pw@SZ-0#S`Sj4UdKzp*n zFVA-*eVrL_`=shF{IX9>k2Pp1FZ}WxNYXx{7&LUTIXZ*yP56A^uwR}RN%{y=iWt!& zDY};N4+pCb>B}yM%l(g}H@W!b`Iw|)FX^I7@{-;T zoKwH-14vpU4_p*C?JeYAce?oHd7Grg`Q)mtoTz_eerZ41XOi>*DPX2jCo|x0;zRZe znLNLf^nI8A-2LxS7r#8`lk|kE0^&EYsp|=RRh(tgt|kx4fYVpk_$|cX7c8p<+b|BtcRGq_B~wyhM{| zw(BZXTdBpCw$@r}E7cZJt0sU!ty;vFqG+XRWmiyWMMPBcd!93MH%o+X{p0s%FQ3iK zIdkUBnKNh3oSC`1tS%2sc9^DNKS{<#2BC_x6sANMJolp>ni8YPNHBM8=`tk2a8h}0t) zJGCefo`pKK>rp(`+okL6()H}r(DK`<-9Pq?pGsZcJ1s*QA3G&2pNfA4YnWd@OTcfW zU$G;2?9{Gz8R}8aZ~J6v!Wp`~lj)^M>%&fU^Tycvy7}i9j;*g5U0=7jv1xQu(fOm# zFC4RM$(VfUH~Eux%5>EcvawY~nfv2I9LpQFO<1>Uf6M#H7Y_b-&F1QnAFR6Nsi7zv zf)DkXj!(&H&Ybg&)WNL-3}3U^&ynTa25d^Uac6qI%i~1X%_<|uFtXdT%;Yj-%?E4x zG;i>ncSW+JXjVz4kwRX>@BxW20-y8n8Hvwme8%8oKY7TE!{>aBxBzJpKI8G3h|k6N z@R@{9IX;u|@#Av|KGX2I6raoRv7Z^pRO0g;jkp}?ck#IrpQ*V8x9;DvF!bnkj!T|S z`MUj``$q(RzOS+@+%&7~sh`Zd=A%~+WL|Rp^atNrcUtGH_j|;`^~v4Zy9v++T8c9DtZ3H1Ft?F`FG}E^vCnulC#>bIs0YZ{cj|D zfH~zGSi^YcBzP~3>O}OpC!zn1H#!Jl#x{aketde=$lIX_OMhkG%JJt*t_(7sPZfBQ-B>raArodkcwN$}H8f~PDe zk|*gT{q>%Ne$YwqH0TrYZ$1hBR5(2k%6dPCfEe5x3HU*LPQ-tb$e(HC(&^x7PgCgw z8lUA;@QW%j9@qGe3Wd<*Mn1;z6eH8<2_oQ zQ#F1w(tbv^;nDo<_+SOv^_-yH5n2xwT0bC@CsX%V79n6NLC5D_yT4jadwh#EpAI@k zJQt@tDUd;dwPwdf%vzY;qLjy zf(7-B%N81Q=Qb>@TO3?4w|e2VMr~7F&{(jfp?0ycAXr;pZ!8NgU0mI8z0uGZTn5r* z!Fko!l5*~Xd3E*1(%O0T^-HQr6Z(%MB!uB!!Qb@2Lz+PU-RsupT$moB9QixcWESiZC_SZgeR95u$g z;F1OLTEQia4GpzRr7k!%&6~TRZt=YOx*O0;?ILM_f-P!54XT7aTN<3ZXkHy8U0TcL z1zo+Yku~d#vPqLmMM`9R^}*Vulj~~hYszXDEN0Q=l*7L`SbI(FQeQB*v~GSQB4zSS>UUwnLaOAcU`T}S3+yV3Td6ElKH;#>GLhCWo>mjp#?bX1v8XXVjWeTfJmyjjA?xE<2|5OyW`u zTClcUdUh!cE)amuuUWKYu^x)KB=Rp)EXr!@YlF2l(CDQouBlr*w{aOjP@t6)^qm5p zsOz9ET~bq9G4C2t5fmpXOB`(scF>qxyV&Ng$6&z{wnn})F}#bfIj-ZBUsNXAL=HpM z*Z||0*H|C4mMpn;8B1r_hCP4TvIITQCdwBz1g~cU!eIKWK;St3)8;L`_IO2bd?*a- z%xZvUYb`*vVh+ON1X9kZ#b9W|6@eyKa*B(Up3p|wNW5#4#ajSXzI5plX-5r;QXs@Y zp9Axj1*a{ksasH2TT=#^;ypTnv8eIKsH3XNGv{9x?>My}N}Wl^F(u%iR5~|*OkQC; z+mp*5GcJxT7}J95s!Ozs0}gZ$a~I z`1H_FdK0HeTtc!4;JIt1kA@iSF+>13LR+e(C0@sK1<`BdL6g%HoRkrNBBWFIfoJee|9C{AxQk$lYn=} zv4#;%z}qn#iw`E?Jqh$j67c6H;O#h;@t9shrS#xpkED!0_0lZxkpw)J-kwMEC%s;> zrOcUt*QykJRs!CR1zC`tfVX2`;ynp?Tc^b5B;f5m3GulJc%rzip6$3`M8Nx;KU z;*XVp&x~Vnu9twfZH~pW6Y%{K=&KU&rzGGPCg6F7WkxPgVVZDkqrguPrs>8u2>b|Pnrv*1zz-7UbdEI( z{7b?#-B^Rb_YkJZ#;OGVAz@DOScSkpAWYMZl?Z$@VVZ0#SKu26(^O*~ftM1diN>-7 z{vP2>!iK=}3DZ@?4juzy=ywUzL}PmdoPKef9e#qtHywGWKRnSJZGzlZc%`8W{Gsj9 zTA=*lM##9rn^hh<66$<{;zTbzmojy`Te|@HTDp?(G0TdB-ae~V`>VSk&9Y)!nsEQE zfyk(5LD)+&3&YGh1Kqb@h^z=j@tj%!$`XD5Yf4b)RTAWNj$8i5AXG5cNV5h~}$F5V^1r^`pbT0+yYLP6Kwq z826x70JI1r?_+=Hm8-4LdsfQ_2P-NAk(7_lr_djO$i4YBU)T?1M&nqk<-)(uL~a)4>0^a2d<#(YUi3Ul`{_!F z0XA8^89g^X-3peN4K;(5;)wj}*wRO1Lsc@@$`5b6}`>l5Y z;FGu0azA{~s-99sb-ZIj}8T^hFsrP1;g~MbG^Peyd z{-_yw)qUoy&;iW7Umn4P3LWU4SprGIcZp2sWPdS_M!$8_Hi~^EEev)QE}h*HHH%xw z^;@cKGgZCszUbpv|i$1ks=_%Rkp#b8ZX6akI+LWiKEwm+iCs=juP zzj_-q6TYzm+KF1#rB#;stQGo1DaYM*kC2^6K~5^Daa>vGSMgTZaW)?yhow??$`4&`Xw9=rJsZ;xo^!Hf9M17=qkXiWhmBb zTmqrJ7?%vNK~BacHV3t$O~Baxg7e#6Q+=Vo&-900f`(vY7POt9(emfO>JGT~whmut zTd>Jry*&_ql!mgsh4#g%{3nD-b$Rp7%j?1h7{4Dd{Sjz{FVyzE7aic%1tPy@RD~h@XTCk9`a=g8ut4Og4iuGz`?PO9 z29)onFPN0MFMSRSniv3wliMFBbp^&|2-^CO&z)7SCg!xzp2w-{r}-xk>XtbWJ$8t; za5S7@wQNa_+|+&S*s;%FIrq7t&3J;bP^apCXDsWt&CO6xS*I15>IijN?y^@(j4mtu zXVqy8Sj$^Ufe}Zqu&R?cUR}In<>ao`6iSPxPR_kI-|dR;b~1xv!LO$UsC44SKfRn}f$Hz^wI>gVy~m|{jSRTzMs$Pp_CT}=sa3s04YO1Q^L5}H zyBtiTbtsPeleWW6_2DVAiw~}-oym#NvLC)rR<3e*$}5Vy8pns9q``*{wskjtAB#h% zbauFO4lMSpyp9F1Pw}2z$!VTQlWC#6_{KS_W1&Ym|KaGftkAnx#%{r~tJc%J4&@Im zgrUw*r8hZL=#AbD4+jTng@FqLhp=s5o1#bc<4E^o(ZF((-HSX{4Xa~h!6p&Ap%Jxy zv>kT0Z-hw{FQ4tc{Wr+8?R2;QoQTV7+_(Q28695-s^6O_z99M&EI;r#t-oatFj)iP z-*Mifr*!DkBZV9M)dMEnxdFh6Q7v0)u!MyKva0{%ZXE)a(M_Mym2I~|Ev!N&Q>*)L z;DAi6F5D0>KZ#b7LOj8pBq?eB+CQ~Ac|%vS1LRW6-MUc~OmEBwukM+a6=~TF)PLOl zB((!n^tHseGOt6&t4hD_P1qZ3Y5u~~*iXf2En7_YrVJp0hgzSvLS4br<9G`(c>DBj z6t_O#_(@l)VNH0HLIv+_Ue)cfBH!r__S?5sk4MW#X7hMY)^ZwJ_9TG{k;0XeAosU+50IKX!RO~I-XD>TxJFJ$oijwB;$-&H3(~$;(4fs2~ z@do#%0aDt0^t|BM)}6tT%||_rUiN2SrY&!mInmRY<=&Lq+R^xLp@xRAR(>ja1D`VJ zH*(>3$6#4HENa>Fd1woSJ36`XT=H4!_w}$(%{tFk}^q!Hr;HINSYGYP((E*w{mbeFe?PVZo z*=qWV-(LN^YMCpTj6zR)i1)+`6@~An`6sN%WnOH`Fnim+V2@-GW?b+kAgt*Oe;L#0 zfVU^sl@QGtZrMRP5Fjcx!!54?Le3Fx*`;zxa408?u#0n$9eV}7RNGk~GW1!{1>iP*@-b{G(v-q;hO^OG zf8=r#J|qx2jNNkdOO*N|mv*;3Z&g2!eNSIZjnh|6j7-`&(Y$V4^U*oMTq{!67c`e+ ztJ!6Zcw?Uv8ezfdR&f^?xi@76`$VSh

ZE!d(7A^U*Qx)~%Qv{+8{StliPypbdmD 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¬Hk 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 literal 0 HcmV?d00001 diff --git a/libs/shapelib/shpdump_autogen/mocs_compilation.cpp b/libs/shapelib/shpdump_autogen/mocs_compilation.cpp new file mode 100644 index 000000000..bda67f76e --- /dev/null +++ b/libs/shapelib/shpdump_autogen/mocs_compilation.cpp @@ -0,0 +1,3 @@ +// This file is autogenerated. Changes will be overwritten. +// No files found that require moc or the moc files are included +enum some_compilers { need_more_than_nothing }; diff --git a/libs/shapelib/shprewind b/libs/shapelib/shprewind new file mode 100755 index 0000000000000000000000000000000000000000..8d11cfcf6b652a8b350c846bded268c75b5d59e1 GIT binary patch literal 147184 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%0A=+F- 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 JQc%U{e*xZ46ZZfB literal 0 HcmV?d00001 diff --git a/libs/shapelib/shprewind_autogen/mocs_compilation.cpp b/libs/shapelib/shprewind_autogen/mocs_compilation.cpp new file mode 100644 index 000000000..bda67f76e --- /dev/null +++ b/libs/shapelib/shprewind_autogen/mocs_compilation.cpp @@ -0,0 +1,3 @@ +// This file is autogenerated. Changes will be overwritten. +// No files found that require moc or the moc files are included +enum some_compilers { need_more_than_nothing }; diff --git a/libs/shapelib/shptreedump b/libs/shapelib/shptreedump new file mode 100755 index 0000000000000000000000000000000000000000..ac2e9b372d242f9788333714e151917686cf712d GIT binary patch literal 195808 zcmd44dwi7DwfH@`L4=TJ(5O+Vj5=tLi;03J3OWN5@&qOjNzkY$gj`4@CTTJw@luFR zM)GtV#A>VU(Ux9LkM?qoy&Q_#Y63z)YX#~BwN<=7LsSqe#_PP_wV!8_Arjkje&>&O z@|o-hpBeV;qW*L9mnwB z?Ks0R3TQfCkDWU_9I#0z!b}@4jZn%J+GK}^cJ+=#nBY*t44cN$0?z{$G!Z%+E(MTs z!fVg3RFcr8B8jkE7~<1mhlz5+o|M~Vm)m8RON0)a|3sK*pR`TBm3IE{&_|wp5~1MA zr~Iuzt;D;(uaaL0r`q%qVWQlnloLMx)sNFgTx{1jl3YBtJQ87|AI@oNTyg%4bDCN_fuUD=^8Q@b-dD{~5gWwF~de zbN|QZ|Gw&1cW%FP5_xXEBF|&^I&xB6KlY3|_I4Da(=qPK^vq)%PM0HJYB}AJo|@XZ z+>yC$TuN?dnj^>O=v?kRuDf>9+2h=)n~(QoJ0=M&`3T)J`JTl$kM9(|Q~6Hgdk$X+ zI?m%egYWr#FW@VmLcSNOn8R@q;VizF@b&VY%eR=X&bO5Be7^GW^Igby5#LMsF6LXo zS0r*d-$|aL_kYx1>5FtM@y&LPxpx0w4`lzW>l<&paMLd?`i~!{-t_X*Z~XAgzkMA4 z(@Se^{bb|%U*u02HUHXU=03mj-b!E5p~!@+3-1{_W#z^n+b3Ib}trLFV+mZgx)7iW4+PP}&4{l!Z;|G79^6Fa~=B)o~{$Gz9f6D%c{qH`P zahb37r+<3+JFdQ;zxd6n36H+mUs;oRcq-ff;( z`OI^{3g0hJ+Ih`QwM$P~^Y*rl-~B^weE!|Xe)Hkz2id3pJ=4*(@*98oEOO7sG;PGs zU&uN3D7j~%EJuT1IRgG|Bfxt`fL{ZB7kR@!J^)9n_wWetH%EY9I|6+F2=L#I0AD)- zT=eQ_d>$A9o-=|xJ4V32cm#M8gVsgf@Xt2^9F3n}jsPD!0{r0-;JG8f?->EUVg&fa z5#R+Qz-7E2tzBXxjt2kx2=Mzyfd2xc=OS^vts|&#-Y8 zK>t`rw&P&H0wm_j0UPcNTJVJZzmWbF{La}HT@8mxWlGjXTvYD+m$Z^oX>Gq;P|_Zf6#{CZo{um z)N8}lTtVI#8^2r>mCrixyV*>u}lliTS+* zIDby!KPDY!(BE%Q*8JY8{TTm0kZ0|*M@h_vC}r(4TAJnk4?YEhNq-k zaHnAb+HCljHl1B||N6j_&&f6&kKNvcp8VE^m)r8Z!$NnQmY{>^@dNn-7n%7$fw=LKRC}yf23LA7Vt%Hhx0iqL4TMWp0MHjhS`C`2|imbx-uWg z=Q}oh`CKb4<4QjJZ9X5e`?127+hQAkU&z9H#D?E$*SqoC7Ca&UUn%^tjvdEa@WlTv zoBjq{Z^zkmp0?@a4{O&8Hr!KSQ8<6BO$mRrM%>Ty9m|%r2U=@dZ&+5-u*y+i-xO?b z0M^>p*c_-=u)2=MfTO;pwXWIGTG!Ur(&nfS)HO9ZT7!XhRl2%nl^`ywuWnS(nuh8& zM_XNWQ&UTgqdm|TXsNY=CP&R6unBU@mO-z%Wf^$YfyS0*M}2!;-73KKN!4FhcOBe0 z>T8->+Up$GSp?eZu4}oz4yv_K5GIS3YQQ5|Thm)dI@+8p0(Z)ppF zUDHv$tiG|ix~cI-q0wfwYS}Uo3eu=<3oN^?x)FBT>gqsO;F|WJlxcKS=;f8by|uL! z4b`o6rL_X_)j_7^hD9r`t*fDi(#o=Ba8|dnu{}`NR#`T;sinEDvU){RogmMJG58~P zxiBi!{QjYgipJ|&o9b**AXU@_=2f=`%35mc7Sp0c9d)(Uf$F5Xg^VK7aveQWSKJY( zYo>z~fohuXYiwU7IK>@9Raw<8u3O#MoS<9b_05A_L@k^))YYt-(-Lg1ZC`YKU0YLi zt3XTY0;SFMEl5UKummpY4Xt$xtFIFQuDq_L*_P`vL0lxdw5)Uyu-eAvWx@73 zB}7XuiS`YN9jOPTm{6Vvr~bxObxk)Y>8th~A(duDN@_?nSh1F9Q8}GE$eFZNb-^IY zP#G^`54QU1>Z^lI0llSV6;*kCi!HrdwroXvd!peG5e_7KUZo5So7Kv;#_Q;Xw(5oS zoMKefHPo?#y)PwHLWfRWn=BZU+krGsSAG0$Pl6wzSn% z=v9ix3K?U7E9#Qf!cpQcoilgYxzh_~3`U1y=T4tF2t9B549A5>e8i@tvOcx`WTl$? zmp+)1oQx#Qp)!~|g_Yv?y1%rq&HcKPN6QngQ&@eA2~GHSci;IvW}FPiaZFSK%V}&J zCp#0T+UelQjkru{jyyXZI7!l}jv4mEme?Oj_&pnK$7qMW50Zc{x8a%ge3^hJ(!2i4 zMeWvJiaiCY^xhctWI%gbg#=1pY#v@YZE=hB;6n-WBcNKCheEBsCsOdO1~~?QSn%hO1~s& zQSI16D!oV2qSCRAD*dFSMU`V4RC(qtZW+w3voizDj>b(xSpKmr8$I(xSRCr%K-{>1;_mRQg6qi>k&BehFYw zo2130#P+H5wUQQ*i@8)< z=+$o^tv=q%y_b2Hcq^Aw=(oJv4X9R+q)*Btq8mPUM?p_0o}#S}(x1j>y75tQ!FzgN zx?76seLlCcw8aH`h$^KnE;#IuPI|YUz0BxrQw8Jt3HndfCU!|7haTFN8R}2*J|-Fz z`Yc83dQzZ~C7BP4&iIXYbmRFCf3DrrGr`f-6WH~z^eiC15x1eC&r-eGcYC^eg2xnh z^=RQ0P*P(SW_aFM_oj#6%+=z=1Omdru$n9ye#+8xE9l!f2Z!vBt@ z!@o46)Ob!B5WWO0sUK`#WR_bG$F;6)lnC97ShOx#>*&#$W1(+Opbr>urN%a7CYwa$ zUkpt>>UU4oqm}M*JsNQ5>qejX;}%uy1(xQzvF&k)I0|~qr@n~Cp*z*F<~&6GEixaK zoJ9SR%KJYr=earcX6sCs_zdKV9z%&0WBq9L3#+KMrh1&@h_(^oq-Ldg1 z%cJNN9QGNN?g@&Hd5Z87`BrYh;X~SZpF7_iV*y+?pwRr}Glh|71IkSkz#+})M@$HD zxm2ghR!Pz$Nr^N_q+XluN2DZmNownU#D7(`P;u>xzz9e?v~^)}XjNXQKLhj$BGlMb zNQ7?p89DAifG*U(DJpuvy#6$B!##A1FOuWdx*i0%xS*$C=VM|Bea0T?zu&+CVX5(i z`SVpoBLTNl4<8Pki;|m_bgqQ{YX#|mS&2oU3%((ZkIw!%^_aUqrB`~)lNlFEk%IN5 zkjT}e#|K-bk`JW(1akW~>1ds~8?jiu{(?v>I&&>(3AMQ!5X7EVsy6fXM2_Fs4|Mfl z$@_`IkH>yDq<01Hl^VOR(T&&j(3=O#EB(=oN1CZO zI&Q8CW@o`?{P+{@aykB?P4r35>>?6N^k_x_pR7#Hl1O9O zy~aN(KGfD6@1@gG{c)v)y72|k(R%b7zrRjKN#5Rit@0%X!c*5zBx6}7Io~A*vD~E) zD*sC6le#u(}Mxu8kup?YIafGRzK{67#rac9hppj+DbJh_%UWPU3(Ua+S) z<3p5BffwvF(;&$tB%`^Tdi2@f z0j}LPmGS3~+|0<1&TMWP9B+&l^E65TWlM;W{;6UNRURvJ7{}E5syA|dmU*S6%?m*@ zUpcIb_>L^Hm-+-%kKW`mr&#C{1^vH3r|t=n1s<7l6jk0nc{0IN!7Z1WxnMA|*! z!`k}0=`}ryofYezSHD4z%+(b;b0RYyD2-ffj=cZ`nV|Z#u7wJD<{q(L#(uj6#gY0f zvskgTD4psaKO)zhBEpHzY(EluJkZkUTHR;7Z8pj@6Pjzb)q_Xxd6aUS%L z`k^_RGyNdxd~3!TOc$zj;b7XM(jF_V;=1`O%Rq0$5SsbIPIO*MX=r8}jp@J7vV%79Q<8`;hj^sI6W+7td|ZuV$w9#AlNxuT zH@27IrTudvIe7&=G%4MjOfg?kyJzjombdZZhnVOISR^Uu-RyGF{OvvtChCg~JcGwz z!YuxWWQ#qH%+qyaGy!9?geA(n20|xcD`9RV<3FMIuHBM=!^km1rQ2Jt|hIjfHGWP6X??qhcj!G5?lK)I)uz z92HA1>I=S&EgqaN@CEgn!-33Lnrb2A=;PQ91d_1-dd&DI5$bcbS#SwNkpIj90IUT|z`jd5Ax;j}K=d%Y=pe z4D+a?gh}gwE_We-f*zUKLN`^>h65k!zwA@n4#D#o%5kRdc!ft4Q81GfaT^Og6j2Bs zp@XkMW=DkAyZ7_eUb#D!8kYK^us2x^H&R74VsWLAemPQ#S^DRCI>GCj&3--JdHQ<&_yvlJ6p2NLk4~OW;!# ze1E>gr&;kliBGrUPKg(&cnmst!DU7-G@uhJl)Q5UI70zr5b?WbT5*W@-RE0zi1^(_ zDsDo==PoQY1|R?t6C!^11p=IxEBcgVuAbJ6~LWTew7aq z)JTSx488Y2uE@lL+JoRC4RxRU5&`-E0?3zmv9{@RzcC=u`4%`&;`6MyQ{ts6{yy{q zZcM~qCvVmKjZg1)`WeF4MLqUDKQ zf*EF=S8TlEGfc+BcyI6fC;7UY+^2|Q5@YFs7N0C@Ba^Y^Giu!~zftLS%Q}u#g3moe zys25b5sgRKp;0zZnwM2 zZuiNwyXt7|4$L#}d~c}D#~)B_-d?BL92-68{~B8m@F|Qqgqmw?VVsGqeeRPc@APh+AQmW8fGmI#}cy^bF*eBX7Rs11d=zp1pjS8t3NWgBQpCW zT2io+b^ESN+uw}LIA-_zM!q*PBXjrr;keP79-PC>UebiHU-@IH|V3%AEI6TRmwn%fYVV|KnP z0`W&{QG#@uf)YH3cu@k@a9>q|(?Cxs0SIEiS-_nF)Ka`W0{S5@=9WdrPl2N!YQ9Jp zIk0I|Y8+(W$oK+TorKe=V+z^kkXY#5j-&~M#dtx_hd-BPc)9d9;nLMpRyf$@A?gDn zAYH-<67!!+jNPA;AC{W@#&*_+gPS&5xEu9@)xL~-!Y=aZxWoN09qq^v@BCUAEoCDm zMK}6%<9(K@<^_PftYzcjoqEmA(&)|O9NMN6*IW{vvu9Sy^@W|EE)ASl8ug6>snX2? zZo5AD`Tj9#rj)!B^`e6i(>6H+S<(4>#L4LVBxUuRou5wEx~9MkE?R~x#t*;-LeEj& zEDL|?_lbiV)BAeS$hcBuye3BA&-R0Au$K~#A7`nY*0l>#kBfZFpF^k=HjG%Z?)Swj zGQE*`%y>65^jO*Akqr@tuC@bu(HzHY>RP)QuQIO9*`g@GM-H`4r&ift!ZIc5^|>?I zfkMs&dxlI)uEoYg*!a+^wTx1tWWAuvPLCp}jdv(?$)4xb#(SJ9<|5`&v3z3rD&`^P zQL%Dj<+NbAQL-HS#jZw9t#;cVq&r!X_=L0Ne#}Rq_m3h5*@(c&Y?8$a)(3&a9Hla=0rb?{3k8h%azmb_|3)#a#%Kvk+f}=}C3seQvq*LPpfy|e@QXr*3=1bKD z>=+#g^`y^>rssL1GkiX(^p_g{5Hm=Axr~2bQLQ^iG^$*?ErV7LYKJ9)j}s#3+Gi~h zFRd1@23p-^9*@ zEAwL@_P&^`fNrXYtm~2fG(N+Xs$*JfHD?Hk$W0yQ6f44VJ03_=V?&%ShRCBkq=;Hh zjaE31?i~aiep5<6Y7PS45`ZkR{zgRBx#mw&*%A?T0zRn&66cKI3vMXc#FBo-mjWpYycMlOy z%)9Ke$-MhGp#Qgdmnm?BdAEXwCFb4L)PvUCS0fFOd3R`592#k6!5h+PGw@dvbKl%@ ztt)L5qXdnk>{m;H%Ago{{VN5lw65PuK}PR>a>WL`PH0V=CKcg{40qYB=^HOs{5Lgu zGCH*#N1w0fGU2EhEpRpcp1sswVB5MWei`cij(MH1X1rSPvRR{Id-aH=FiH0NkxayL zl+B<{>2q)AEVm42-6JiHqw#SxtPssuRkMF!S+wDzB?Ap`K~yHdd(iaXm|Tqe6U)KdK#nz z-}YT7?Td^H-{f)>vqc#0gkmWc%B>rrP6|tWD)DYR&Uz)Z(T=lh2|ZxPS-pfd*l`vy zp@-}^tHO}%K?of@C{8Lvn@P%)oNKhQ%Y1oWjS|hH^c*|$hG?n(gnab+HuPxjs zJ$BP;qArx3+p5N;l+G+Jc+*@#MwrtJoW{8wve$=Sb}HK^WwN#VOW8*W@6oz`Ld0`; zTT1YlvhbT)*Igv#STYq8Tw3#-(k!}L>^}N)(cA`>JmJ4dVH6)lTE{h7bqqQ=D{0W4sRsA(i`ztriTyHXlL-3#&%|7p1W}$+xxyO z#ZP3pd4jCLoyK-!2g~K&_hqe?W9$&%c-dj_xsONsPIWiH-v9r}GP_MU?q4y0U2zsK zkFg{X%fMFnyRR}}SmH%9ZeAj`^t()aY(l;WmhvnA-~E%72xiDX5sT<%ZQ-86vcrAW z$eV^rQ3ZRdAfAJ6b;7iiJn!oZfnVvKA%!lWkkV}mUG(*Zz^`O`heDT7Xro=z+^;VL zex=(dg-R%-Mhi9J(H>>%Rc(Yyo508GmO_gtq=prRD!#rD_-q|Wq01?x#vg^Q`ualP zv*#j(mQhFzR0`FMTqt&)a!f_eG6mFLJ;D@Ve*CwuOaSFtcsnOs|3_}mroU5x<)SS> zEpf+i(MFiYt`%mC1K#*$9`Vsusie#R)x=~Xx^ts`g1DlL5C|6M!(A{AKed|3{PrJY}8MMi3mdF#tZv@;}0wIP-t%aWC?b?%8} zRr}{&ZP6FK@1*H9akEji0{h7v9D7U+Y>#q;J&=g)<@}9(3_n|CE`-r_6?32wdsvjf z^86)+7~#MHJ~8%4?S}e{#a~&XS_s?aH zwMFcUENFm(-@`%qQR_dQLR9{-R1P0%k(lgWNd4wGyJ|C?h_w0h7lmt4w?o91d8=aU z)PbMX-t`qC&EBKd_ghu+Yuc-*-UpV{b2njZsxf6X5<>c34Y^swv)ukr(A4?I?nMpt}5seGK1&&YCp{QP?Vgj9<1ITH$}jK6OH?y z6+wrd$h_+6r1PQ2#3EW}dDU=YV;Ny7Wh0}lL;Q&jl*lcTj7Uj?F$$kRV#|$G*6r|~ z&Eb95=uQfAUYVX!2IHCnZ4{6f7*u5|aljRPhI6V7N$ZhP<5_hJtcrDGU&cjkE{bp@ z9&l$R3AoEGXF13?v=^!3`mRKebv*xVK%xt*{Wg}-N7-*<$7ftTT9Mdo z%d*F_z27#n-#=FEMr@_tSIxE5f{y>}a_MgT{%xg4Znbf308Wcu5Kd=43l^i<8_(f_ z7U$dBwXV_7qI{bw|H`n!mJRs)c~$tHBMQqZscVc{ULP>`3x;t(hP>1KJBflGb)W`} zQ?kg+!>#ra7aN;-;={^O*RkQl*7=zho&yuilUW>z<~jH`EaHmf@(S zBqY6YIRsW4|G$9&^L8qfq5ms)CkW;^OCn#E<2sBm4$rpuW$2ecz##-Ztehoed+1da z$|lf#s;86I5osd%Tb>a0NZJar`^`+V8M)75q)UWuS^8`6IWh8IwL-7bIrlv$(o?m1 zxM_t!(Yk(QOLl|GJ79JbmZ9>Q2{sFQVoTK&z=p?Yq|zTbjyp$R*-eTav74kvE39pj zm((`N%W3-L{@8EXE>M1-IhRUAkT(BMh?Fe;f5?nHBL9DT_6YvHS9q_qZUlg%v0qZs{Jv`P0rP{uQhy`$*C*Le`@WGJ3XE)@FE~$h`6YE7{sl*g?$W z_(iQiViG9_GM>og9Y79AqzcH%M1Ir>5rCf&U$$J<8PK~rT@i%N)mfv+kn&gOq}b)I zo{*}LL0sk*#FY()v}IETv89#R3_)DoL2MScD|<5iMLPgIE)@lTBD+LZe~3NyG8)+* z@)}<(sTi6c{56M4jXxt*uCY8V$8DMBIrIRw$Y%iRNbl?HhM0V~UD7W*+L@t!pJ`nm zFr2)hFHY3D-mzj6wD35_GD_$aY(m*qcWlnv=(yFd{nXS#dr5Q5?){U%A7=sQDAN|b zFO{-G`o7Otm1+KNPdv`S*{{jN)X1XMX&wM3r}M_#T(4!``qaxe)?DF@UdE}J?0rOM zd{^kPw9HZWK_XdBd$p(+9SWR|XA|I%BP+*iWSz+L6?~;H-N_o0X=@9oUx$LPcq5~k z)kfPD$g$i(m3^~&xx-)c-omK+J<{9&_$JJYD{%!}>6|q*2%moAraZ0ddOPc4vgDkF z+*WYg^SM}jI$~kepzYY*o828Or6p?2Ewqp`LC(~=(IiJp+q#(5#aPQ;O{m;;9bt0{Gea=GTTDSM*7+k8v_#;=E|qpJq@{>v|L6 zco|?=d8*0P*8d(b7QT!w&MSk_e1CL;vhhCSnS#Up$Jzde9@?H6>T{MBeHgf@G?I0J zF+f{6m(P%+#f(hd7z6Zt-N+0)$9W02#ujsH4Bg&eDL;wH&}HrEGDjZU%EG?7k(!g0}QFqz&NjV z_tsE+qShsEJt*#aSqpzxB9Sh)SnOiC&X$fYQFubgJdrX19&LD8>pDQL?4d088Bdl) z?sj*Q)>Am$O7%v)nR<#T{n-_hEjZPtIk0)Iwy7x58c+9)aZmR*VRHv;(h?l@G`~Tw zWP+Gz3*8}Y(TiRPzAgNFL%mM!A_hy@gY+PJA9rn{^Ep0B@9o!UE7Wx3$-rFhBV_84 zW4Y(77|{)9;5DhlAFYCqLd11!q6)4sz{rg-^4H*-gCv4~lIn`1S-nZ?n;J$+q@p%7 zz^>;7%oJ>CwiZVl2O=|WA=(j1za{D)m07e~>*_^@z9Lh*Rh}+F6SR zW%u{)KMC}yDmI>&LP2$=8cWiBGE55g7{v%8aaYGDV?_%;z`#dx3IoQi%R4xQa-JCO zv5>lUOV=3(6q5PlC)Mm}XPp6~dQBzQic#?rH?o%l&7pm^2lhxqD z5Bj%G&~T(Q=Uqa9FtX7K)z+Uq?r?!7jArGDFQW>GOC&yzU1nLjL$vS-Vk>WXLM-_a)22raw<3upV=epzwETvQRC}0c>t`}= zi0lfJhe}SbxHmpbmyDMu|H*i1wa3d5=EWK>&)efgNCf|sFd1sxgnMM@Xk9yDAl8Eu zE&h~GZZdM)QSNJ*gz7v-14|c7o(x~?n{lmp>mMB&)D(t zuA*JqttPXi*bn1*ui9o2D>1hL6A^m_k!@i5$->esK@-$yi?lPLFKA5+He<$}zLW*E zvB+2GZh&qQ&Dbrf102SVM=o2kWQlB^eY~GDjDd-hw?v!9*ZQJU)im!j-ZxEg+r{Xg z4Gp!i$6=6UJd?;6FBu#I8LOINyV(RAvX5Br*yW!}^Se+*S)@$2hU2$S7Z$@4_%F9B z8lvMP zGJX@eGXB(Yn1nJoV|R*tku|n5iz$<%y4d$E*Ny&Bk1{cZ<6!71wgKF*T^topmSbT;L322U84}=(J58>JFW!n+vn8xDy@f3Z19BBZW)fT#xe=eHwhaBzHhEzwG{92IBvC9QG#gzMDTOnL*q+|bGW^0$F!Yp|Zlu_ro?y#{pB}vd zHZM)1>XZ2LnAiav(q4FMgvVv@_^I%y+peAi9QoRYS{&DM<>882WFK< zl3RtBEUl_aGuUR8mL-W!Nlvujso+}}QD^^VEX{1ykzslCI_CKZ2QHd*ZtMaga2xxk zj7h^0yPI5&f%=~uq>7)1kSJ~ejVok zQ*E=-11lYh6)tWB-(qo*89UJ;8oWnTzL47V2&1rgLSUr;Jl==h(l!Ni_dl(WV1EM5 zm}p~C`59`hQ#kaSRRh_7UrSnF0!WFhkwz@Z^hDH?Tv%Qcl7AKXXi`TNnj}tu+;c*>dBnTdWjh?V@C-Tg2v<11KTg%e6^=PZ`h(*7 z$rX-h&iRa1!x_no{B9Suhqh%Fy|3N=KAh+wbvF*}xRVqQ4nD~B)xq_T7QPGevgFa_ zLW)97upSy1y=H85$w1K-t?OJED%!^7A{Y&QF;-iD%UCHE+CgP7{`loCN5qo}@Awby zz{$!hJc~KtOzSegJK+*e@QeoR%d zSDAta_lJh|SAEpuH2?M|@j-~OHzoIW-Nileyt5zE7UG^FEfLQ@yu*(s}UHRBhb> z+5EXB-ubH7rg_PcK&LrfO3=1UQK6jD(3(7asCjH97o!d&^BFT2TG2wH z=U7n>QMW`RYvlPot?NV*YJreVgaOHJvpg^y`JIdnwwq?4>sr@q3?Ogx@;Fl!rm=EE zy7)QPhC6FuHp{mJKT!9`q^VqF=hl`v?NN@>BG<5I!Alt6k^6Fh`!5_E4@Cnvr-$Qf zm$R%&XZO8|W4CeM$j!%nUNoSsKY;jn)>F3Py+t2uU2zd7XQ|Qj;{t9qS$3p#>$vE+ z=elywyLCMD4tDRZaSB$19$mxM-VJOJimPTFu$33`e&h0Dtds^CGTU*Cu?s3^dpCMhb#}& zMaH40x0GRYJpw|Ur+2j5&K56@C1xL2Jo&J2nG;EWketwRwH#c~F?q|JqMQe{b>%9p z45*KnFZ>3_TxrEPHiEg~B<=7S$~X(XSUWEFhRL5Yo1E=U@FP{Qn{&O0|LlqBL@osNj`X z;17hG)NzQ1Mcl_`9;>TZy>&h^H=2G&G-n%lj?FIq;RO4372UOuC>C`ufp&Wj!-|d; zL#1{76%c!mVx07pU0PQ^VkVKV65GinQK%AP5A>8Rq?L8D&TeEXBe&GJ%o%G!2!l&R z-tdtzk?RPmacX(U1*W7GV%ibyla=Td*TjCz?tQtewykv>ird6#t|vk0}l+V zn^km)Rk7+DtK#Cw&!um!y1H0yPCbJlVk>NYn%g=k69(b~u{Q)h`205KmI+0&f7#B2h3Ikh9BbT8JpX$*$tW|E5 z71*(Sa}%zxulq_CPUZOieZe=tMOXec+~oI$L{4DQ2G=RunZpl;Ui%{S$vCa+?{Lbj zt92=lD`NXX+nnNjNq?z6^rmd{7I7}?5xZ>R$b7YuJ_N-B2}kTo)uA3-GfR(_qDT1J zmonU9dGtWSUfC0vUnVf7RI};#7_@}UiR8!xmYa}%SRO@@YXxa)s$@dtIypB1#kAN2 zra(Z=&Z?kHuD+DFWAjy&zQJxVK2{x(&STN@ss=m3SIC{hc^!d;xJXsFNXyEi^>Qf{ z;nSJcs|RE!v|C5^PXylrtpl{RpxyK}XsikXt3_2x`<^%`(?oQUvvl(3{%B=iZof9D zFS3ywSY#VOX45Ri;w*ObE-U0=kkr7-rD>P~bpq32?i#UI@O~{~L&Q zNk8DoZgYC0zL}2LJkk3j?cX`rKV=dUMo`%aW&fCD&3(TaZUU>WjNQV15BqL<%^}%I z5vM~sE)y%AYsP=8W-t*y9uiqvmlGYKhj_z_GJb}#gkt$(qZwk@`5 zXASj}dC@~d-V;6d74Ip$qqv+Pz{ z_h2%ZQbS*yqpg2Sy27%>wA2?V$4SBOkPS<9-ZHddX&<$)VJSx~9HoHfz2#GDfwK~S z-W#2hCP&0vs$gI^y+&^^gVoF~r>tR?gMck%`SKi+b!cIEe|52OnYCg`7%{0k)9igz z`pjCk{P$oy-+XW|UTEGgab*DqZ6%$QCq4oj_gdE%khj+*hpecqOWq->Jk3|6cES5K z%oInjj29e!Sf=YzZrhdizLDO4JbRCrJ~`xiO6!slCFF-BrAN{;dBEb_!4W$&kL4%k zu|tV@j6EYPscXoRuE1nWF@?Q##tRprz5rLZn7USNb#QGe%f+4l~?VF`}i>QfJxZr%Izuy}60~c`g$aJ*{

zs#(rR?rDYDm|a(Cr#=3B90El zR+v?t-^*!rV0_-yd4{{JjC zUQkN_Z|^%9jCr5t8}Jo9x=)c;li|%bt5v{dt^fzOG1$cE+o5$W6U|gBfE_&T9N;~C z(xsOb#^eNWB)f^FOe0%nUHnzFB_$SnfhCDDh_Vi6YuYQX%X?}vR`}<#&s+1cn!%Zz zho*6J)-Nd|7BDe|i*;dx<1t~|n!|mDYJ^y=m`~Q9vVmcVpEjHOI8w zfuDA+Gy{j}vSr+1!4hzLUT)jS;YO+Lyl{Pl{Iz}_D^&C75u40hVv&99w`0@k^rVKp z=3Pv~Ze>1+Jo~4%E&%1lLc_CZw zG7GH!U}y};LLjm@i`z8`rITeqWHE07a7Hq|KZkR(9<580n#J<6B(RR>M;yIkNdGAo zgJjZ%3LLK;&MbBw>ydrIaAr6Bj%;&D__<0TLziz_{RjO6}=YFih^QcsZ`Y$(Z z)q@DiYg3@*u`*s(qF%mWJqS_tKynfx<(b99LHXvn36MzBDmW34$TapJs>?3sIO9QB z4t;Tkwq7)GNP-?D$eaG0$?n$a3L~;ZH4<|ZN#}uvRNARrHx7nI7|!ZkqyN8$h!@(# zDXJ{NKPkG|O^xbkJc&f;izzl0ZM`AtY`K?;o5*6GXmzUB9dD3pW$QkM0IvnzcNQC- ztT)piVZ|TcXRnttK0DLl7`$K1gO8&?OHRKvEdRw}>D|N9uMSK9aaj5{!_vPPmVS6x z`g_CDkzwhsVd>6c>6?<%p?C&O6c$#Wf=J4a6bb8zXvR`9<-&C*QbTMRS0!l8jvA3cqYDb-$@~)k|_-CgXqo={RaEK>d+5dHzVV(;vA$ zzrL8e8+e%e4*4`^#?N39&pSol!6Um&azXfW33X6dVgcn|X~AJqe=e=@g?TQ;cYFxShL z_8!u%AgijEg8Q_2heQ_4ETu(T0<%OwIa`bR^qSqJ+QMD+UTykIQab1P)%Sw_()D}l zeN@+e=TM>GQ?~w;Lc~woc4^_0WUgE4-dD6#T6#Y%Q)1;_UO3&@GNsZzAi@oOnxd`W zKr=xdh|W4ruX)B7En$P`wKQQrkUgMBy#vt&+>RBVKmL~2`v~(i!+NK8@=Lyy7kE>& zmLlj%uEM8pdZrZhO&=h*BAq({+wi4$#G&e7@Kqm=&)4jf{HDLC{Hf27@sYIXFRM#= znayZv?+2?(^$3E5SBNe+&}3{tt2+ z`yj+VPucyc-1#?oNCT6&$WsvSA0sL=YqZ=e5YE%NI(Qh+`1G?#j-NGJveVC$EFQ4{ zo+a_|>7xQCsJC#Q$?QSK9F-w(dFIW^I!&@tR2EU5edB^LD~Zf9;|aDrx?|r!hKaEi zn<`yZ>3&l>C3Y=M7~Btu-Sm?q&VOU8etcv)a%8@^PUeZgX6UfyYzK z{@1?pJ`~P@Cg@MU9F7N9878W%UVhro`LYfykYV2VBU&1nTaFhR zxWIZnDKCC~Q(jAootYn*=5pw92!V2RQr83#GjM6z6o}mVGis zKK<)Ae5kdI)+VPClsL7?bDTs*X_He3c+1sfucSwNwaE^JK!o>RfkDJVA>wtSiSiO< zc^32XO#aQ|-_ob}Vwa}xSnXz5XUsTVZrxSwLRBvnoP~n3LzG?5WM&}mig8X0=S6T% z0)@-7m@zOMNzad}=S?5)REAtVb!uKK?L#*6_3(Rr9uGO(ar5YQST13oN4ckg@$g>k zkQcrXs`tIdTtF^_`2^h1lE8+-=4soV8Pn%8J{_r8_NJ27f_b?>}%dQ%o*+;pDnBFrJoBb*St zmbc=Dw()Mk*Yui?)P@enDRT|q#d+TN5+3;Y*u3t32C{l}ZbEkgqC1C!6O(mEv7huB zT=awo_qoAlPLp1LR>oDNonv-pPvcWF6OQ}4EWJR-d6umrvbHK5UvpN$%X-aLbbcG| zFVFXwuTY$6{`5$3mAqnq@7jG_Cka$U%BrwSGwf%Bm0l`*emKA!ikCb?fVn%X_&b1nyu$-_wQc^`Vj5dbaNwRB)9N?gDIj_swwp=E+qTaRdnDWHj2VCGfErM1Wn=ew z9$)rG9PAU68Bdp?hQ`xMH@{5T<-I6HyW`&|jNM`@U7T{u>zUWS#U&iEO{!aX+-R$or~Oq)Dr&0DvO z*W&?q6%UY>aeIz;1faDqFymBRDV${X|G}z1)H8+`0YzshpG)!RQ|waSMR{J1Qt3WZ@=gPC8W0kd?nweU z9mwfGNbo)tft&&43?L*ps1}G^D9Hmtf`e*-Oa?L;2nmj?1tRC$a?Y&|v(>S-oPo<( zxJs~FQ|Z2d)CE9E_}tv7t8||aIi6W!2RY@v4bl#chIM;8Dspfsu=tn6_# z(4AfyS!+EmWCYwfRGzC$PizJ_=7f7>BQ-sf_sw%hYA1wBBk68@S!*a++|Sx9EDKO> zoP^(J%1Lk?Tt<)NrW8A3$4T#WDV7Re_C>2wShq~jZj+5XZ-t$~%*$I5$_$fNmHJrW zWsh6I*{=3F*Y$$t{JbH)uNxwyH z+3`T2ToGb)$rT|U2-M{ge@g$3XnJSHKhVuyGj+Cfve$sd=(IBKuk(!*)6!Y)=nN5_ z!wh_)yow+cZ|MuM@{cZ8zFaI9Ia1!v} z(G*^#fnt>CtG`J?o*$o{vbvt=9MPAO^3_)gn1{%xdox!r41JlZ>I?V;!)X<*T7ACY zbO?@f_1U2>(<~g9;N)63%U2&uYF#IdQ2=kQ_Pw4Dw~BvNYN+=EihuPX&ztT*CP^l{ z%Pqus%JkEeHS?I#y~eY~)1d)}wth3TWD_7-vYbupz6SBv%DCPvFD+rm-Q_o)G$$Zg zHVncdXjz4oF?GJ|#a}?_^eE3|8mm3MZ>O3$92}I^TrS}9$b$4zRs-sHhM4~i|Ax;4 zr%4%mx-#G4bW9-|I2wJvT>~(}+;z9&6w8yNERV5Q3xAJldGJb_lw^Le16p`Boaxan zHMr#0XSkrkS)CqT?P8akV^w!6_l)>)7kRfQZW=dYdd!9FQ~P;k!!GLcNAGq&B=r)? zBfom|kM4s4=PkR@-@D5J`HdHC0{EK)e)*Xm_2BRUfAm-Gd=Shp*dG>qndgt*?%p6p z;HXuo$)n@^;tpOTr*QHlyvy7LvcXgFFDgo}nmwo--e8e>ORhCaerq}bS+;y9;ZNA_A1Iag z4|sVerT9}%;7a5sX(6r)GYhX+JqC@?y5#4oA9o4U{g7e#fg{25n?QLVfM4EE(8?u@ zj;ub96C{Vcy^bf5;7WNlaJu@1rGh;)-u!5@ znp(J`xaMM6`8lK?4wwt~C@Q@8DR63Nu9Mx2o48r9J+gpDO8I>l4nV}|ui|ykvaW1$ zr?2gkUdSBOQJ$mcg||}ukv`p!|2vG4CSl}ecX}wEzNVdZOtd^jjrD~8n$lzJjxJ8I z%~sKuH@|Nz$b{d}Ct2Eh`N6rqxtUqi7yAc&z&JJkZG-Zw3to<`AeZ|X9`wIg?rTZ| zzxV^5-+oXN^dk#0`+sMSx-((l)HCXlwYla`Il_`w>1;^;J{et5lO?tw0)mF2Y z{0)lB(T9Y~PN`VE3+i*Y{OIv2lIkM6`3IrISFOz#w2FO5~GPTL5qWp8ozkK=Uk$EN8)WsAaM0sJEHFXC00e~kOwwkA^>e>Asyq`FvpStl^ zoP`arn#4<&dhkpv^&Wb4X~m_LIHNt_a480D?7{S)ipDmEPvqFBlgk z=*yUPri)OG$(j_#Dz6S&$;+&GJ%PBr*WmH4;Nf<8|DtoSr09`)gLX{d)~n-{$OTh; ze_jIwE9SqyC$i#-XudKfa(}yM`3}K}cn#7vQ6jN0)|=nV_jsYb`khZR?RM2O zN*@30{cwMf*WeGnAMRl#?vdUP_sdAK`Lx&D>i5L>O{D)k%_Tn_H%&sON_Mjj`zP~4 z2!30&_lq?1o^MkR)0eB@<%GRve@Xe$@*c9k$q(h}MSl$qxC?bSAc$w`>)ii*oIsn+F~cD-ZTb=4iU zb*+I0$Fvs5v_{9YcJwr6A)g4!laV34Ons&XQw?MnLuA{!OsjiuyYZp-CFwhajsCt*wG}P5j=ZOXDGgPj+wH4X6i?CMI9gV_Jp+w=N&|ON^Ny3|6Gxd5`!So{6 zx%ma>Pb)ZgTK-H|!MPXCm~mnL`L4RQmZ1FlyQ{dP)#X-HFoN<~n?#bg71evt!lWN? zchy%Tpjy|3XlIp6gym{%ch$&m(AQce=YbGxt8=YJK#k2SUDM&o)u4X;UDU&Il>Cl= znqSj`5Ss(-ih@o0YmH$yvH&QtedN>W0Re z1_oE%b?svmrS=vz9H+Zn-uCt&18Ai!dDV$Y#NlKiT3pxM5?tBfx~}fJ7FvZks+*cx zYN`Wu$mN?sM1v;SnR(3?L+!IMLes~Tx3#Q*?HgPx+FDlCHH$4%jpA~qr9euy)tHW^ zCfD`VO%PN4fz=Va(pK9p17J`V((iVU4wV-TQ$6z){ems%Tlvb?xLQ_RTUQg9?wThW z+unF%ovWt0Sq3WdMMjf?t||PJDl9#q^44~ko_2A&-qNzFefqqLy1G?)lSQUbNGP{O zRw`5C7wt-@=ty)f7p_Mlgt>r~6*mMB$I*x;^H)#D!qGYPq9PEKKzh{XslKh{x*-9& zssq>}iUiOMrDucujZhv|l$_|1q_RO*f^MtbpZ{Y$Sy;DvPO!d$K2WOS8d+6_@oBYp zq;^{T9Kow9Us2uM7`VZO(XCmPuwJVhP{}~s4I(b3h&3(O*R@$qYiwrhwl|{Nj4M&V zb5z%^ZVWJ#WZtp`IM*63sM=uHV-*t^M4OA71Jo=HRdcW6hP|0))V)#E9PMwd4lp@1 zi>}vKw<~RAL^0t{ml5M*gtfKYut@1HJ>1^V5^SoK$)Sc}!z3akzn+h&uIBOS)O*gD;X?B$1)-)x zs$c!&?~TVje4Q`G1&aN&7JbuJS`9Q!UAj1G%f^sA+V z8(ZuOW*)_PojKfjEj?!upthE_L2Xk0gi5h`o9K23hn|A3s@zQNK#v-J;oC%^% zdAEU<7FTUuU8_SD*&}`u@{v+D`vw29^9|J>d|y7VU6OK2+C@`Sxhw~)>gIU7gLvVZ zczh$FPFR`daO8$qev;1Xl55KjM`oBllQdyE`Fp$LarrI12lzo8c`x1$!iNM-_ynQO z@^v3!2Rn#U(S+FX8VAcM$F%ta=%pI|h70 zH(>{1Az?S6pYUG7TEYhiI|w%u-cGoKa3kSf!rv1P5bhvs_#5pc>>&IH;SRz)R$f(q z=a`-_^ObnKiLit4Zo-CF!Iv~Y`I5^^EAAznN|^b2Jl;iE$PaG4NvIPJ5LOX7*=gBJ z=q9XU`=OOEmwo6z5*8BfC47MJUBVrNj&b0zDKeF?fzU%ZK-fx{$Nu2$gxv??@n;D$ z+3Gz=n9H?scQ$+xRuP(n8wus3c2NmaZd~k0>2Ri;k~KPWL&|8Uz~!Fzj?Q>|3Sr`N zbbN=y4T9kBy#X1>hHbWUUUu$$ZS3mIPRAuDUv&0)?$d>al=t!7a8o=^mkoYq5L?Q( z;g)#(Zvvf@?YuqJo1J@GnlIZGN>2@s$cqsy`%N=>_VDdD9ppNxYOCg_rr+ooT6; z9<^z{u_EtX(DL0Lk3TpPE#IJ=seQ@%AO+l3}3 zw9hdMv`qBsUCLY_WoTD&nJcz}ydC}dGwl@Ry)8{;&s8dA>631kuaNRkzD;yJlm>d0 zrRd)5%mrhYt6GUF-MN`Exj&4@7fKmEO?)>1s|4mdQZI+}e5n6QvNxoqO&m#fRoVBZ zEy&)OR!2Ao%+&QZpxy>pd^@OT2KN15m6hoH49YC0%wA!dkLa)tY%24?)$o7RJ|E({ zGJAR2al$sBVZ+lm)8`JbngohcDYXUq-LXmz~FWE<<(=faT}6{NQ|~kr>jk zq47IZ-+c5Z?a7Rz>Ur_lw5!vzcchkO?@DbY^n$x;43Sa*_2_RV<4NAxvX55{{744! z(drtqJ*Zb|T6soxcdDMf0c!WA`m#5sHULfa9+iQTv1#K|ZS*!mub}?Bifl+71l$RL zPE2jFF|Hm%q++aJf<#4LDw;nwZDEQ41-X1|+6^f-LNnq2$KIPqS5;(fTXDkKrX5-w8x<94 zZE>FU_dL6H-Q0V{*Z!^VTkHGhJz2SD?_GO8d)IKP>YO_F7NPyKoMZrE8w!(YlpYeI z(O?)I5%)daKo2K59AfD=S@#L_D|25!UypL(LD?Y4X1|CrSR__94zjl(b7RdQq|Jov zJIF3bZzBzL)=-ZAYtTS`+d3@vy}+r)3NWfg4#w~_WQS$Q-h!-0ii~3w=OJAoqYc~E zaJ?2In2&Tw(PerbWNkBK3CKz_WP>0p%8-qNEDy4L`oTfpGZpW2k=PIVSq^z!ihTmI z^^h%wYyj1cO7=%X*!>)n96ATYN21r=@jPOO+Vikk51ZArY3TR*%Xm9KX>>TdW%~UI z`rko+Gxc$l;y)W>(z=&152B!r}* z;~x_DI8Rs(th!fz{Z)PqvmtJoCopW=&kl*tOJ-qMobf*dyK%2JjJ;zZ+X>ke$WCYb zJWyN>ZER5Ek-mMu6W8#@rnXhiX}QN$9pyNN;h*!{ z+aRmu*n6P(8uE=fM8Nm*0W&@*PAvX@(r(O&W#RWgSgCb8()ZZ`p+>|#c9)ZYH3su& ze8WNKJ!r8YnWx1_8;7)$nTCV1HIUs4*})>g^@sEIkZp%d+O^D`Ml|j*t8w)Nnc<;T zWMf3_9~b+b&@IJ09mOFBuZum96+yO=667a!Z1``E_Q z2R5E0J{AJ!ws(L1^(^`r)OfaUdQ9?=0J{!p+3#Wgs6JBT#pKrb-b$Uo42sj{Y1n)M zoBwtkXI_4SO^f$`{dFqn1GX8Nrwy}n>gux&G@q6-AC!gm2pl%O|2_V<1pc=K{svrbn%cXso#>VSqCA7an$-hJ-Hmd7jHa%{h?NY1&I^*EOCkY^P* zKdtF`BE|iKp1=O(*E2}+Hw<~WasFv_jA^MH@+Vy^9df9^2u?ip0jnJb@HO7Ho?WcU-jI0>iid|-0A)JtIZ$ES46)k zzw;og_-jMD2=FLN%A z^Hx1)=KH_pBU_3@b?Cr>y^7k7os8ED<`s4CSk*C6(Pf@+oohSy=$PnQZl&_j(6%|( zG}2x1VGCYu!lzB&qF3Ur+R%4u!17=&-Bh>^V&5B9)_zhetF&PB0hA%K`m--_`n%^^ zJ#Ln8pu_67TkrJu&$C*=%qvcfi*dH0N6givduswuzCidw7DiKq8}Qg?L=5+n&l;rH z|Lm0Z&VumufFQK1D@cDN%%27Do5)mLoPJ+83mNuXK)(r{BEsM|01572{LN$TufI#fyE6NFqN{ zJra8ZULrq{&W=r>{AbcFV&em#e<58It0&^Gq}#?PNH<`}B;w~Hh=>uUN4yJDe8N=6 zZ=rcWm|^i-5I`g-%*c2@G9h8c#d#kRiI@{0n-otFEoP>GnI8X)YFUN>&yM$HO13a_ z<1H9XQ!^7O3*$#JrMVdZrY?RN^Kz&e31(S5o6s%HslYim{xfPOl4s5Vvm(x$|43`I z0BUREO=weLmVsFxZ%(G8Fq`7}WI73RQ=AWqA_-x(#M_gpH07|lKYlw4t&7CAJSiNR5)Xopzl~LmtX%UVXfJ*TnLNYaFN?%0$m9!?9nU9IU=Bha zTEveaQ)tS-6vba4Q)GIBX&YZbrdXInyp~KWGZHC1;(x_(pH*s30#hA75}#SEO$|=N zyhF0#j{ci7`|^Q^8QdZKEe;0Ld>Nu^PR@SN0y?kYBsvVMIfXWvxkd7KE}4N!GKAdB z>JTb0U?=2~oCq1Ki=aQ~Lm96V97C=7_~5@4`XhmIRAne~3PcC*K>S%{rX&0wd@Wj1 zR>Ew6yv5a^*JRB#x1+trM{v(-%!UW=9ql&Z65eB7C`$bZH*>NrfW-S(` zMf_WOsTH-Ncs~LxG5o>Ww(-Ga>V!$e4=1x!m>%(bGRuUij?W?Va>HB(GQNpScVWiGcT%mVSWk*SP2ApQ zI83I*S5mEyq)d+wAk$Zvnei7`X#K>^?D$KJvRash@!^brfVmOcb@2zOHc*&N@qVm= z!2+;7zKSVB%{Hh#9sh(W!z5*=&CCd4UWs#iv8=;IZCCsw+8iM%yW?-u=1B850PIB@ zVZe=8>O_>z!w)G3GYlLMAH0U8ca$`fgFWbEjWloK6pB19pEPapAY!k}ddG~!IesRU z-j&$B`0dQqd%_gOe{2HgLy4n0zL{ztN%I*N=kit7Ua=n;-@vkRHr$v}S#3NH;6W`pi5Ijd&k=`P}>+CoevXUcMCINZc@AUkQ^H z|A;m5wJ_Q7?o9bs>|4MkAKxDQEIzWnGYfITcv}l~jMGct(H{sLfm8NqU^n_$5E`-X z3;{&q>y42WRxP z^RA`AW+}Bi7AI)-8~HOFRgiZSO&^d7W*E=Fy08UhW6hQVaqG!yDoC?&cs9Dr9Vl?5 z(lL*sFOfZSj1)i*^7Uv;=2*j?@NeW}L>niL2O{QTF3OnW46*$6n`&Djn2D0Q2&pAI z3km9ZOTh40n}tVp66692aw=e3kB9B&s>s3F)EX|Km(@c4C=|-h0ySX!6%`XmX2eDco5bM#!oOs%OY*!z9z$6IF3Fd7^c@^Y2=m*L!1u+st`Om7=OU>ttpC$Ml<>T~FGTlra zLPriW*_2~aC7C{-D4kRxJ=3y#6AXyOumsDgCJXQsGtXh&O{~EO#7ezXl32&6YO;0C zFx+B z2O}NZWtzSdMP=rii=FWV8b6?k=_UL?O0!zxN_dgBh!zm=Fze0h4(ohkUHV5&G*G|0 z28vQdyE4(vH*GK^NfGgGw|xHr(SB`+OwlBd->UL#gSajGZ;*q)7Y;fi=41eX_RpC!+-U~UHh<0AB@?<4XGSAX*0n#dAST+;H1Q1@wh?eqH zK)eSXb^s{Xj;^8ca{NK%b0BwhPI*)OONUY9b^M2Ba|H(5-c}x{->`0}wi^VErdG zcoU-2aT?p1ytL#-j$@=uDK7JJM*C1o6~+)gR|eAx8BB9!tgeu;I+s%%(=j( zOU*=QzL@4`9>8&eGZmM>f-S?ybaNe)yBdZui);)RSXbUxo72hGgRR;E z+hRPV>o#q+XYTtL!S=#6(e(^MZsmi9%fYr>h7Yrq{{8iz)OIZ-hOo~gp*xH644q}{ zrs1P|(U(YRwnqynKTp$A8*J2n(tq`!>qj&- z+3=p2;H=N3^)s5D(tULtq_R464|UMyEMb9%ZUmFs5iYQfE>jmn>vpT3U#Ot_Q<##~-m6e->*YRqwJRZck5h_L_ z^U8151nNU*I-}%wAp74bPBjazW&%vgUW52nX1y5*9y`Qlj7cD9(+kgTZb3q|Cb~zo zrhYArAB6Zt8jscVe>h_}q@9!3(c#)1&gOI4O#2-hC*MMwOMh@S&2XKTbGYD<>Bq@; z(`H>qj4~2iciOD@t&OyWleLg=4as3Po=!VXA}7%93{6kYTe4TFrYH8UkdtHKt@k+l zWwd`t?bDlbC)Z*u$m6O6OB=+Szc`RP2=e*?L5@)n4rMj4>rsTh;eA!z>Y#qyhS^8i zU?jZ(sIs0Q4o0v&D?pfuy)yONj)MFMC{!E|f(^AT9|$djr1u;Ud@eHrh;8SBc^6Wd zOvH5^u9{uP6NalHQiSc$Ow02$F}(?zX^hIx`makKtWc!$rtlDy)rgg)a&K8R^y5ua}^#i!#V_Ingp!k-CF5O0I-_l8y zj)GDgm$1zr!Z(!w3@pI=oPgvNJC5A~ZzFh2fO?6lFNUupR6Y&zfk`=F0`)ubxVqyQ zO+O3i$0gIfjuTa03;CR+d#|IrfY{4iWaV(*X}+p|22sa#%5W0)SP~OaNBzGfXQy)8 z*vVZAv@3UwGo=R$MV2E|p$OMe4*MRY8M~%{`D|DlHXAwDlrh33C6H{!4TD&kSY{^m9t1d+`1!l;k&(HBHmx&NaYM-MqM*F78(8?>S z?*?3RzG+15?+thofc*CzJ1}^aAHOg#s57`W_;2iy8tiAN_|Lk}4E_ZI{%1XC2E7H8 zm+;@%BQ-E^l@GRu;m)lR|BXFTL@X-u26OXb{x_*JLw-fP{HH+&Z@{6j<$rAN;1dut z|FfF;25-Qb|A8*P0mtIZ|JYN5zkw$I1Jiti`9&E1$HM*rFCjku2eu422q*pr<_+v{ zRlEQ8*8yVQ;HwZI|FaJA4J^1S@ArTH0J^WC?D(IRBW@ zWc<&H`UaOmm;YJDH@FvqR$Ra23f=B)k@{4mSCyZSx4F!a;OQoTp zFm|al6cWZRm4+f_IwG`7rJRVC+(9 z=umSU7`s#&YGLLA%`TOO^2~BDcBwSf+FSrNyHpygFf2y9R2u3ij9n@XbrQxdm4*_+ z*rn1?rL6tgrP5FriOnvRhN{d(@biRS9}VgHXlN5NDeI%5Ye?Gl(a^Qbu3aAuZDww> zQJvi>i);bch!x4O8?y;f%Gwm^l}?(vJ{sz0D3|roP_?DGJ{syTbR=>sK!T4$CCm?5 z9}Qo?7-W4kyh2E>kA^Q4@=G{^9Zd$K+n%{99~+x5|Cp81J3vOXHk7sjrSMhi?Xx-q*x8Z9&lFm`=3 zT4V-;vFoGJVqxt1Xtb4?fE2qv8Z9-afwAkO(bncXFjybWfjjzd&g{zvB4%)hbifCL zY0kFLoSglj1$4OQl;|+5<`mjw<`&65NF|wpN-~7S6jFf!J0b59MaWoP1c!q@l<_*j zBx+T_v@R(Ol8r>pgg{nDqh*G@i>!`D6XrU|?doWBuDK6gkgSeI=S$PHtE16{!r0Z( z=sCjJ)zRo8sXV(n8eJ@mT^)_qike*=jV>`Cqa(MgqtQBH?CNNAsW5hRG`dU}yE+-9gUtRj9nd#o-d4D9gSWfj9nd#UMP%R9gSWjj9nd#UM!4V9gVIO#;%S=FOfj) z>S%PeFkBstRvLc0OjbvuUCqTPCc8Qs?Pgewc6Bt`T^PGM8tp08c6Bt`+l+yUT^)_~ zkrcZ+8tp5LT^)_~6E}8sG+Hf;T^)@MFn1yVyE+;jD2!bljSdz7yE+;jY94`_T^)@M zlN7r;8XX~wT^)@cE^2mlG*JN>_r=4z>QeyM3k<>59tsHB9T9{{cv?O zdXzL1SsjgzH19(-5_wKOY3fT^A&h-2etdQb5hEFw5TzF?!e}E7!Z2BxL8GjA=xdqcyySz9n&JxPP%~5`oKF$z? zndE<=AItZ`O=H1Gyx)|+hDu9C=`jfN`Kr6}opD!{Kc8XP^cmzQG^Fn$Uq?`z&YQjb zE1AA5&f>j{{BWjQ{yFla8u(@{vHr=|LboF~`ESy2y##VR5(;)Ap=bxSZxUhgC1`CU%H7Ej$@%cp&AAwF>f}49$)H!22I}M4Nq&%vrS=yRk!~bDtexLw+&~r@#JByi8BdqLP+*jp2 z3LNl+_!@lvgD6AOO86@Z!LM)NUoQeLnJN(v!-~;Fvx!$4A-2DMOKpyX)LQKQ_1D+t z|B0C>vwSPm(;Bp}{*dKlvDCZB_2;j@sWyk}eo6ke+Oo(bgoFc60Oj}#^xNQfQasZ$ z>8luM?f=@ltI1M(B$u6zoJi%E}O~$3{-Gh=@dvZ(xEan1ZpV|1nLEWs+e-DwGW{} zJDM?(S}#&m8YwF4h(~w{ui{)yZY{}USvWwacf^Cu`rA^I&`fY4_CuGE z{|0Q$l*k;kul;bEU&8h}RoYWoYqTdmqFfK1e7>Gz&Wvz2at0DQb=EA>V}c$lQ9;{J zv;hM|jxS(oD`;tY1!XGY)d^`-Hvn2H=pQ85sJ;P#M^Osptgm^rJOwGnE_${!sq1}=UtuwtGI?2Lsf|9v4a)tB2UAe>q zw*wOou{OAwPN@1i_Bx&VDu*(cw;{?d;B7sQ@%H4M*%;U6K`i7)^diQ!_^c|SW0#{G zN;b9~$=Kvt%v3Z_*lRcDE@oEEcf`yzF0 zL}(|$=3)t(M z3GEI=dG*p}1Lty>!f0MLu=^lw0YJ(tL2Mw=2E-E}tljWTyQ1hAXSdJUHSVN#-9cEp zahZ0-(Us2bc&gLiQfGHd((V+s3)nC*!bP8Ob~~NjSI#a!L4RzTHENe^nx#=}wv*cB zW@RWI~liZ%BvA)DWnDIjC6YWK^GJ zLbZwRPlw9X5U2_uNCw9VRA-h|^9e*n6U7|SB%fo4pTBb%&ZJ&^MWrqJM>H`Ad+Ghf4Vl5Q{++Ftx)w;C6yb>{6S> zXV?q821}ht!;qz*PN9yVlcW49jev%_C}=r|0;US+RB(wse+23jwiEQ^=u`)~$$>sj zP^Jp#uLRxyN1#r@!yMX7i9YB+dv(=Fj|Wk}Q~|vLT;iuc0(A=21U)6%6up>a{}l)N zJwcf&phs2#^dLSShoHOcmUpiQDQAaM=sp zsXE(;$#je<;GZEPA)IISd+hI3pp$8HmIJRd>VL{ND~|2#9xr z7pi6x7toc_T?7weIMi9uQp^S5XjDnTH7LQNnq0#Up@LsKB{K#D+q zVj*^ z9BrSCRw7J^?{jB&NME(<55g92Q?<*r=AL;zS_8Y3$zZ026zeGfkYZg+Bn#Cu6Y7QN z)9Fx|8Ul5ngW7GOSPGXaRI>g3BkHx(-1z%}U}?7@!BUt3!iI3O+Q~#0Li2L;Xxg#; zt))8K-}@knGc_fYaJA-YFbFN!r8*@`R>%j@i(M$wp(dfMB*9R&g0K}*uXdPz%3(f? zKJM(^s#ZHb5D~i$AZ!*kt6j1}_C_1$q*X|!hJ-#E08$|}M6yu-%!K+lIzAmLQ$wIO zIjH9>6f2~Iw%BBad>X9>lr*pZKut=a=>W~m7!Wpu0cuykpm3PaqFn2g3aOzCkTOE6AW8?|d{Xny~ zHkJhsUa2j z3jn0zMhvH!%#Rl;)JW!}N9;{H#uD8o{TP?|M_{dn(Lf~=y?F|I!fKDXAZumkFwi_O( zb`fjtnWJJOoZVf{?p0?eOSN)6PgJ}1&TeGvFSO(J-0nyayq*_=|mJGh~*ZiU6h#`QdHLhK#J-GBH8P^aE66QLY)|! zmJXGvAyE4rRPLxG)Zk30NwK@qp)xfDsxJ^Esu>MXr)5H&6#FS1DpNzCRywF{7K%gk z6AG1W^NE$4823w-GX4~5QpN|3)-paCguOyuQM<6SJ2y7d*_};wwxPc`yJy6Xb@Op% z=;y_@!7io4%+!$3KLdc2LeA020&Q`s^_{Gn^JBh}G^k7sf$9SUftqfiSPBaiD&lf; zQH%=(QVJJCO>%Q53AVJ)X(-qGDz!sjEr(edTSYrw@3~_@@OqyGqBv7iLa9fJgz|R~ zdb{wrLXKoVI6d~L3*!sIu~6HM)i6#6VQ(>BR+~E7%!qyMZ2m@7+I;P7jy(o8(lxd? zjV`e$V^5x$9jhpXIxns@&=R|QNifUbh#f1iquM32d{(TEcFc0&u^^b`*&vEDH6_dI zkRn-r351s7w3#*rz{p`vi#-QArA=gN2-MdOs%RX|q(UxIDD;qWn3=KW7@Jd|GBpHh zAP^*~Sr&@-dp9dovUxR+9R(+DMenw58n!`ZQ`bYaGw=S_Pqf zm;-+xwus*P3MJ7$iKzLJIH&WCXn9ofXvhs$R0=$ z$oU}jx_ll%@F;4Dih4D+if}BE+n^#j`;G*2wv3e{Vf?H%$&2B&*lribbI_77{HU1X zOic-+4N@eGsZw|H1fm=ccuZm#J7Ueyt|W{VP?0dWh9+Tjm;^Nmqlen$(h!GvI(7=} zSiqAffnWh&38FYtQ^I%{DH6s{AaG}rE74%?0}Q*?qF8dqw%Mc`x!BZFm9xKvh0KDw_;~ z7vSL_64_I%`u}hN$}MQ(Qmf}~K`RP1tNY-9t6^B|_JBsY$Ze+f@pQ?CFlS?Ie zY}7wpF}Cv-0(6Hk@Z+U|*@>s<6CLgB!TW@nOD| z!#l}tXGT#DMrgxDf>L?w!N^+=rLsuolf}&B+qSx*IIIR97?}?g!(@IkR6Xwlm z=?{ebPk07g7rhq)y+2G>UTzJox`&vse+WKs$WIsJY&I_G<6gPw9^xw(e88N?U*AxR z_sPqb`?`nt(#Bw9JAZm3r1uJO@LoC<{Hm-Z|15aEi_%;C-4Cbv{J98oScpZ@5`$=) z8C@zp(`66gBu z(9`LzGc_a^#{odxpGPFysvc9Q?R398^pkUc6TPwp?k2&4&pXSxe^PCdW5T6XF9s@#6Z&K4bnyv^Hc213;fKo9%8y4O98kV-u$WbIQve*;8 zks3NR&9pdELtyT55xgl8$R*oJp^6>UlcD?4p)xfD>K6yqc0LWI>aeYo99s~!xjNLQ zQmgK8s7Q4$CBf=`07TU!Rc9C46uOukHLl-@Z?|XRXCZ&hneVmIE;X@!lm)h(t#-4l z#B&s)z^3DOa6;$MEBl*{3qWv6I0{5@rlw?K9#W(-9|eIdPwMW*ps$j{rIhE1s)#!vIm{2CV3*WdEzZ=CQ1-Y`5({Z2&H6%xN)BH? zhWY?XuHK`eCS|&S1k3a?}-=$|cQ$wWF_OK$KRmE&TIpqK2-K$z z>dK=L0I=&)CMzgIZR2oe^pxUGd0Bhy#NsR?-0qh zf#4Vmk?a!NhR+6+lmNffBO$aV!4eq8HZCR5RPB-#P#%6FJ%mgR3E?yVNC=k^$(BH8 zh1$*%h=sp%?(e5pmcUyi=w4QV#Qkw=CLwGi!4Te{p@i^>+LaLrhdCrX7=2C3xRj|OA^Z#gDS}ZvcG6= z+JlNXJ^{RaA@lUGeHD9ujl7WQ6gyfyytf~gJHruhA$NxJN$}2a1Bk?PitFwSfA7`D zr`ISRy46?J=2#Uyh@k9i;p@V@|G^It)W}`xTdG*Z+Pplx0D2P3D=rqVPGe~eA`#W> zXT{uG8mV`&RKB4eUdC`#`JpoJfT=iC!ES(4J}E%6O%$qZ9~3B?51g{L zYBfng>wCJ~T$7#~r?|fdg~bX+`;)iOgBy^6*=*OKFyw8qzEuLio}wBTE^Y zofRrnHZy--IJ+0JDtBa1k*nfl61*y|rjbms_NdKB+N=lkzR6W+9^ zua)6_=^;`oAvQlZ8KMl<3&&csEPL`yw{WZ8@WK-51zmA>0tuGLG7vV*J_B|sImy%z_b&iI zn&h`cvQ2WlLQSIk>hN{Wea`vnel!VIz(pXe`-?N(_YeOk-F>EpxPJ`*;$FTP>s8Is zIp;U%ND9#7;Y!S@@hb662!0u&OKGjwMd?;0b;heG)aKb)bmcMHAQg?b=IDzsZH=c) zrKQ*Ns!mirUfgFUb-l_DG$+qOZl8^7~k-X&eZowOSFtI_N+4kg_Xz0d%Xwd9qf~&NNwLRJRDr+V!}qpF*;k7AZ0U$h;CRTZR^T%n@LC7FmB14-fbq*h1dgNw zpPmVv9UAX|Uw6PiIpCs809=~^EGt9)`WETHYqV_@xuR$ky4L{@1dMbx(@4nGPT*_R zM2jL&zhwz95p#ADx@y}Xi^r?@dEn`ITJ=(jd{2t}yA=6PDe~5u3F0(Ebvm31je*a* zJ6pNw!Hc2>H_}I@Bp#KSI5j2lw2Z_=O-dqMB_X}4dcAQuiL}`J2WqGsb-FsA~QA*W!7^C?o!P~!MXupaO|=tT(F$E_K=I>BDpBc z*j~6KR>>vd^=`)Ye`e7ACd7`U*-W_4ljquJ2Kik3PE=u@eDUy1f%zG{TohAUSsPs2 za+tZn4R9$JMYq-35+;yfOQ-{3?M_p>n@Hz(6>elU(g7Jp6G zsK0I`=x-tj>u-_T1#Fm}Sr8oP?3Oya8=T#9V#k4gz1rnCyG6lEV3#sHW@^azv>yO6 zKDDT)p-lcB&V*VVd_5g1Q$wJ713{psHbCvkgsKUaqQ+99%G4036%Oidfs(I&#Y$|> zk{PTGrod#T3e2kx=2wC7a<^uo8ND9h^2$z(c|2r~O`OffzDJJ-{#0wpt6G zKW+z}gWFQ_Pg$P24}j0-Pwtwx0#_it#iihXVY=lX2hVQ(ZLz*=9a8!8;pUwHzaYPd z{H6we(Pg-K_=?v53Jd}|e)qPfl`PQg4sd~{>~iRT%J|<6RKVMFv?ip@=3MO9&bxJZ?AHl>WJU#l%Zb?|1f(si9IqM z`*u~`N$kk-#KUM2NpfS7i5#S!JItlPg zWhB7P51)=DMof!%>}-TMz6ul#gZtMZf0XWD1hI$i+pCtFd06+He~j|YF&O^%CQQ95 z;kTYV;|s1N6pJed*PUc(2niP33=oNJs_wF6-x^_K)yDyxTjFuRVJXcN8M1Gw{6mek zyTL=D;7`uq-Ok@T&Y!sw{=WJz{f)@**O?3XEwyA5%v*6VF&sJJB7P~5Wf6Zk2`=K# z0%3dT32M`v<%`3#4K9LRN`IKCA^qVR07wu0G?DCm?0T)Y*-ZeG2yRV-DWFtL%?33+ z5`;#vQBBbW%3(SL&4{!pGBpJ1EC+Q<1Jq81f;$U!MDU1os7wukdeK3JHqxxBkyeE7 zO#HM6?AcP6K<=6%=UIzYJ|~E2kLpvt&dJf*pH%sMDw75j^{>_X^D2B=0ss6Rg{tPN zz?-lCB$d3%k`#HxdCC+W?k+0nPNyW>X)R)TN0qv&5@jE%Y?#W>aaPT)mXh=6agxf> z_f{=TkuOX-@+!_#`N{^|D$X@|5aaq3-BVQlOj4E+C<3UMr%G=(09M#M|Xl`+uO zs@H8C##4-RwvqrC^>O@|R~C@qLalfRdZolfB#% z*yTJW<9v}?>B9?*^ZTJ_$N8sZobQLWW5@ZYWTd_dd=7X0FwX{vj*)mt)o_JrjF$DV z2F=VIt8&gm-&48m!uUKCT^Rbwd8)%)cs)yqd}E-lkImXq_Jp`jJQ6ctdHdu>iQJ6s zaY&Zv@)w}Ym>z$(mcotd!QGh6O#%LLkQv?MQ_N2tH;yysTO}`E&muys4HT)nqm%Bo z!JYj*m$l;VXBNYiEV#8|I{Ysv^ApwVVO!?Omu|d1{3$tea$rls0xnD99*G>;pAI=$ zaBl-n<@2h>x~qIOmH9rEiFLLxqL!P&^es(c`oRMl03Q^1mHc`!k4dNCBlnpoqPo^U zgOYaqz%vLG5D&9))v<_7CV1ESIl=3E75GgoM$2y|FB80L{hZ+WuErEgCUiIW(cgO) zk(UXdM1KlAJwkR`&~@zkc14oG#RV zK>77ca^(G^2bJHrM8^Hi$SRLb#CqM|VkCwyj{D2uK*s$WK_nhfEjRAlF`AbSE`6ip zesOyXwUbbL{mTi(asO>XaVitt41(i+2M~!PRNamH@)QG)FOvP~0ml6rc#t{9ay9mt z#jF5dpch~B=z_kkalT%ougCsNU#Vlh_~L_<&(*k^zRCinqu_#1XByoIf)AW4N$|#S zEC@U1-`T;IMTI?ireoj?*rkm5nHn-gUJL*k^Is#9g$gM~se|eocrYC*Q$wJBa8N^T zNkjImnCr=EidRvm@}4S_r-n#LUdZzS`@AZRQ6+t5dD{}N;v-F( zqe(W));{4?xyz4kFHUiLgkECzT3Mj}JKF{t9AkF|eEGj(gDUPyb#3@gpe<2`_mk>) zn0X*yf%?4y#)ocJOR>(V3hmWF+{q!R-C!dF%w>yr+>)^p;BsgsW}Rd?0| zhvVCz*+ zA|9_IFB7{eA18Kex7dkYH{T3cx48=wDS1-Y-N(ztU%$5|e`^eZ^^o)}NVgNep1!U~ zue%#hy_)m{h2wmC^7f90lFa_j5v6CKWM_YiB*ag^%V01;4ZTKiu-JDa>}24nx)x3GBm%$Wh!GM)&}ntCJ^9{6I`y= zO0Hf&NH$lOO0M>Ums}0#Wy@hUbG6P_13Sr8&wDjjQ%NvaD?lVpSM@*2Rom4T)(xkX zSEoc;bz=&1Ej+qw^3D|bgDPh~p z9p*WodrT|eoN|iE`OFKxi=Zn-@())eKf5Anbsrq|RqXU4`R$|HEm|aq`v^6;3eZ|@ zl~Yv4xDzu|7_EP=Y)n@hJ+31;4xWfQm0#HVmyf@&cO0Urn5;@a3v}{V_Bw4+IcHjK zc*bwq;Y!{Q7+V&t{Ap!T*4z3?mPM(5BXp%K*1?y|?Y5I(^Z0;eag>_;QCVcKvCyu0 zR9)J|3YhzQ;Y2fC`Ii)V#Y9DaRTWU(l?zoy!^-nh7_V%da?32V_wn&AqkWPYm1|&w zDsJL6(9gdJdXmY4t(wUZB$&xFKqOvN^*_qwbj>6JyFyLm0WMz);lT&E6>lkXGn~4n z@TJNmPd}wFRe{5-DO285i^afioFd0VYt-rmCnB@*n|0&$rg3+T{W(v^@2M$!TCbHR z7S)@1f_r1_WPjQlYnh5>ieE}-tt+92T?xGpg3ryfFwaB?_Widrl4w%iuc_OeP%^Xq z@4%~|i&UEpURGj-=^{{uDDx#O#p!)$Ak? zIOMgQ7jz`u&B1Dd@2_wvx24OWBe$hDli+RX^R$w?{enud_p&)4pX3Wof(GyQKcgz2 z@;7||x$LZ3>392_Bc|N#U!h9XgqrO;i%`7V9|i=us^^km1^k(qkEpt<0DD{U$9MbE zqrR%fB{q7zW#)U&`P=RMWj(0=I)O-h_h0(UyyKTO)qdTrqa5e&Q(x6dKv5z=E&KjT0D+vF3HiBig@bGjHGw=HL~*93KrTg!KyGhAH3hOCQUtOVght69CF4-@wXjh^G5)gsVR`XkRp(0gHXu36|#&H946{N$3bp{nq>S{LS||T z?+GV3 zlKxiuCQMO(FKkzT-;n%2FKC??_sERfAQYgJOFwDc3SRAtmu!n|Ki41?pPk;r+%$`?khwez4W8xLtMg zaIa>^JtpwsNJO;pHl$begbrlo@YdTZ@)ba6`XV#23a2gO7{#zpfTZmCYkxe>{7q8T zjlFCV%knCld}xi=IWkI9#N!#YhEYtwNz z%9ROwH<~YZqy5mR?cJ#5uL5t^n~HqN^`@H@hU-lo0l*@fgNCq8<-7|Xt@4xydeo_W zH8r+AS8x)r%IwsUt|DXu!w>q;LL72eyUOrB`e()=Z=kF(4R4@$re3xQnD`j)aruSe zwTADb)Pc9}qg*Q6MXY`tJa=t2>kN@UdxGz*w6V@|wJ-)vcXQoWjhocV-0Lr@xSfw0 zUNhy;`_20h8&pSTt2Zjc*(!cK8D<|OvG=B9-=(TWQDE;g{Ouv>-VT3KyPE|h*xhUd zk$6_sU3a6;4l~||*ri&}0*!SuALYKft<9zcxIq~SuxvxQO&XvDu>lVX?A=W`d8a1@ zajhy&Vz5!)Z0Jd_kGNp}?SjqTfnfix>MmHl{!@dMHyu`7qK>`FO===h-lhzr?DV!W z_HxAhj&sS|OReQ5KLWbl{BuUyG?Y>qTe=_`8LmzPp{85Z)C<7$W^>S~X{MBl=_Sr| zM}z5oYRY|I%w1+!x+$e%x(^oa3jhrEbv5&XFuTtzNjIZZ%(^|5ZWeB>d8F9`W^20H zCTF%R!>mBfszWgQoB1@|j8gITVuo3;%zE>}FniRLo|axLkcwHyr_+NxM9u1G_M|y3 z-HcK(yClObU(NQ@>>0B*-HcK(`%i{hv6@Ya!0ZL{Ou8ARVs_Ls$slEF#vcmdF-bmQ zdV^^;Gc|w3nHmCfC19lWdt>P-8(TR8_gfD6%Kd zc)nZGp)xfDYN3OAq5*2GLbY>H#`kqPRHlYN{pg^EK1aifJZ-4i=qYizMg1+@1zIsj zi?FRE>7x=nLSL!!q1Hs#33O?~t2j-I>%~tYaETFMz#P;l-M$D z;fi)6FX_CGVo8ltQFwXxM}?mOt>?k_?W1Pb!5e?80mZ3bA&6qCpg%(2f0$}9pDgf( zBy6R_7^WM;m)1((wG81)ThaA&368H+oF)Td(Pz|{Y52~GH;@}D`o>)W($AN<265j- z-?*#658}RyzH!{@%Ny7iHoo3#smAqRt0w%QTO^782KkXSUvGINHn1n@Lb2eArnM+s zmjo^>1H82;v=(;)$lr%Re*PNc;1f@r1D>IPJRKy}25sUbheSox>V+pRAyr;b4x07e+tw8(G*7O-?MQPVgAIUy*(ig4wVwe7R1rN ztEMy0Nz36EqcE1@Kkktl@j(`*7x>R=?HkT|>4g8dM{2~KF}!n*|Ezr9;lIKM|Bt9f z3jZ6m9`OUpg8z+Inh|cJ$*eBE5w9Vc|5>@d5pK)M#&u@I^^oyD+SUvw?hW{li-#i? zAOik3e%IRyjez$AT7YhvxI=4i_gtIL#>Sqn&OcDH%bhwA{mT?&c`VnxfGu;=N^ed+dUG4Ul#&a z_DBqVGZ`v&kHp}Qt3cX45`+9shwhOW{F$`fBQf|3X}d>a@K@4ykHjEmvS92Ui9sWb z-6JvR6UOe57z_ww_ecx|g|T}i21CNwJraWvGZ_)uJraX4*)Y-Wkr>P}4A}0G7|a&N z?vWU5YS4akkHlbe*;&i(kr+JGj6sUsBQe-Qc3iZ3BnI?vWU*l=-&ZBQe-TVzYZB2CHN*#wR>qThv4-%u7Ej z2Q49}+a(4!F~721V(=Q0cDuyjwcI+UN32eps>r$d#C;1*9T0f&rQ9^_cXX1ACX*2+;)jYpu-U=yX_JgwQQI8Fp}JMiQG;$xm_anc};GY zNG7>m;vvXGa=XNKV3OM<_5+jLE|E-fyTmbIlG`Ot1(Vz^aVZ#Vm)Hy*=)XC$FCU1Q z!5zYP`{=(pn?-YS_JbDC;U0^k!?2oDXp@;+By*!hNoJsu3?X+`JcJ62(Fr+&79nGG z5ex=>DC2d43Di0VAN;pMzukc~961dlw_#!>{QA>3wxdII9<|Uyrz0ENvDTjeFRiGD z7r7U73)!}AIK@$a-Fj%?Xvq%H+*>!#vKUt7FdL(oiRZ`*diRpV>wn?M1u$)SeBc=&tv{j2Jn+rGskJ(p5Gthn19GhE4jL$8~DN+)jJAI5uY0s zaaU-kRD}Jw`3@qUW-X$RP0aL2HGyY2%*KB*h_0f*AcnmF;IXPTUV!bZj9&41RJxof z)xSZ>3jyU(=JRsa`%}IFMwBm!(pt67NkhpY%0i-KYkIaV77WBW=%j3p780eyi(vC1v-(rX{!Pr8m8-zE zYN;6KH~2uU@QD!W1*cJ{iFP!ZMUUQZ;@$-GlG#Y+)%6-3)F-vG{|@%@Bs-j}6!$C! zw+w7yPyyHeo_pIMMk9(_2{f5e?AH;wp*>7SSI8(PGm5{`k3=EbUnQduwqmD?Vltzc z1~%_?nEwWJYH4Exbv4pUeIRy`_y&px{R6~45FmTkGEu}!pxL$1MzrEntE-X0IIL0 zjBx&3*tVTu1uKx)c6CEyIj6L$*!Et^b4)Sx(Iary5u$Co(UhM!8B#y5;4;xWk!od} z2K!EY8mjHR4q4FSzi(`Z5}f!SUen=NgvI~xQyu0)!vFB|6_aq{fA}t6#Va`TKYW|7 z;(DC?BF&Y5AXFlm2>8Xt6Uj`<*$@MY-BsaNc2_`qWCX?LcnoM$&Ycl`ECf6I_=Lyfx30ye588%rQ zHv2=`s2>Qw*O(K!hW)RZf8GC@q}%_RC6T`WbvQB%vT!7c$s7qLrF0;kZgtYs2_5#o zrrhm+Ei@-|*#DYzIC2dHB|T&&O>2FA|iVi-KY*tuM+SQtB(i?uS-kYeX@u~M@DjGfEHTAP(%FqdN= zPyfxCefdDd4DJx#b}^Xdtor8U?1zj^;mAIx!?5f$PIOo_fM^VhE)kSbD=tCK=6U?Mm1xy*Y6V`y1NnEVV3_?7z>vb$)Zh_qHdL5f<9zw@2yI#jq zcfF3K?s^?d-Ss-QNb1e*dL3IVjNSD*mb&Y8Y>C;A-qr4U9jg<@?s^?tDvaIrI<`z0 zyX$oaN$Z)LpM*sk>gsQg^+MrS5tiOWpN4mb&Y8EOpoGSi`Q@u}ZTAG0U#k zv99={49YXkZ-B(Q$>!c8-9ZTKyI+nWYbu4w)>sacp*Rg)$#_oC@s}{!Y zdL0{Jw!(wm^*T0C7`y9rEOpoG*if?rYIfJ_Sn96VvD96!V~2~H-Ss+_y6bi9Nb@`Z z_M**=K_0W%aEPd#P*`@o4o9wH`{AzFv7@A!$gbD1k!BxM!;zQdlcp^mM1NKnd&iuJ zbNo!mWA94rUi@}QV($r46#uaam=EPKTXlRh)jpEuGc3LnJxFY?*pG~FL5qy-6SZ-1 zKKYLQ+f2o25}Y#Zta)JgpA7dKNDqDxS7_{0L%LZ}>@)KcG~(RRI`+AF2PbU*LN8wm za3pS+udjs3ihqQh#=aINJKmis-->+;xLgFBgP+Am>^pM->1NrWTln~JJskN4pDnI~ zWE`?m0842-rmNq!o|ee6sq(W^80n?%4jwi#{|O+HvqHd602895Wfptk(_9*E zu#N+5_XV$^IO?zFb4na``|suKNTUA4mLkf$+>a2Wxm&*bwdO(*d5usWJj}+UF=NRq zvl^to#w0JVD<(IvV9$5TOW@_!?Ct=6@%J9D_Ny$#jhDAzsFfzd=ayUAIi20i~|~`M=QRg-wOM; zVqLGen=0{n9Z?o%Q>Sa1&f%)_qtl7}MyKRBrxQbM;on6h-x4f7NmDD5DPGB?DqGtY z4{=pK2Q&J=sQfC((FS&f`N@*XEk#+I8>EmosnS@#8bX9gQB5M>DQ_wakie*6hX`l zxXsM>CF6Rj5oYA9{<%{9-!rTyktguHM#sJC+SXiYTid|1EzOr~HvcEMQysSeTpPKI zTp+1?$;lHuooOcB#!K+N=vyqpI7njHB*{->;Sue9u{i-@q-|UNyQAZI11&wk=!K62wtb zs7Y)yyn9m8!7IL4)2>$iS~k<)h@5YJ?s@vkk;m*yWlavo^Z+WTm7~zpCD~{46?_zJIP+6;B0F> zN%&phOAk{J=FrOxa(rkR;7oYS1s3+`WUqW967!~^2}5H~7*+Kq_}S!h0-RjkME*7; zC?9?c{0~IT6~t-aD-cbAcsFh2Cyg!hB$D!nQq}VQ`s$!WGKo~16##y_J4NdM&zkc_|WY9S!CFpj*`g5~SUODzNi z@LBNrRd8m)0nQfu^=pN zII&@rVSM<+zY0h>|AG&BW@hz|CNGcfEWeVx#Q2HC_$2s_$D@>f1N@o4Xf5QwK%wY- z5Z!l!I0wXR5~qW>8APWi>pVHW_`UdDp&}ozFdtJS?`ycwgQJ~h#B4nKP(&uz>l8n) z*Y|dVm+N(kpVw>ucfm_bvHT|T@AD#?>Zfh_d*Fw#ex~}_Bdj356t!cf3I7rJgj~ea zBm(>@U80ccj*YPInIW&<4|yN0PHOH{eHDNClKkU|b(-=kmgK)fW5=&tlFy$gH#7Z9 z5DQyr{@qM>{H7&s&Lcldd~XAO=h=lQl7rF7okHMSB*?NoxY}0Mv1ITZ2F<*3W1Y}! z8&Usv>n(#Z=g}4zQMC|v764$5{}h0gzX5sqi}>h5Y1a=yO$2Dy{UB}vp{9KoD-wb* zXZx>BH{~12V)~pj?e_uo+tTY=H65l1<{ba0Y35a#8UnQd2olA=8=&6Egj(e9(JVC+ zRhb$BRq~-i{TYNt)vCsZlZ< zEF?o$iD}zbt?*+!wHZ-t@HaUG89Eth<;U{laDMdTM;CllWg2un1JXw=APYNdi3KdR zC(P{q69|~B=Bi8$iS2tA+u*%4lzQt^XED$$~os=eXUzQJppB zumChn3^`ZetZtNiSr*-~Owh(*f~Io?+#j*Slm{8Bfh6O)@w$D*&h;37-31mA4O0%Y z@ntC4uKF11s$(BxAh<%+IALIWkk!B36WHk;CR+Q?xArTOIBei~Kd{?8%+DL;#lW#Q z%6>Fz|7Sg>ff!U6r~V{+1RrsO66Xg$~)6$ z|HiM`eXMFs^g66&DZlBP0eb&JTH&4-20YBh?m4jkG9VhfWjqr09O~W?{a3;DS#q{j zo^DTG9!%OSg|7L|N0ZAx(Sko$6;Wq$m>+!qL zm+MOJ0Ut~6QefL@#e+UhE1oAW(+bPC_z!rQfc{kwr-09&!#4V`@V@#<`7L;}{;(9E zuYO|5Ms<2DT=ybsMZ=Vf4R4X; zV%g_t8yqt`Yg{v3c9!~%MPNl7Gsk}cg5%~I5*$14A;IzUV-g%gyM2ivD-%S<(eX&Z zl|OuuMP?~o0AybI(jiJm$mdwB9CnoQ<(Sg>s?YhC*Kc`K#6LwsHjlu%#}1S`1Z+(9 zM_H%%_+ZuR(4JMaQ=WrPT54VL%^)6Te)%-&c zR(%DYk6D#JXwMRT8MHpK6h3`j|hpz2a{=ar02 zNiF+L>TFHDxiucyNh%*2)S#H~EV#xiIX5MJx=jz%uUQ;|LZE)d;*eLeHbvunt0A)i z&J(9f@TcimNApp*B~R!@z{2`o-5jVoz0yxq zlUH16ORY~bB`>A8>W->nV^Bw!M2Vx)cT~qdNtJyOZZNwU0*=l0ge#C?Bu-`%y+M}E z%-F<_Y=Fv*NmMdzvrQY7C`sW)C;F4S(WZ?{oJBk3#`l@N!1~BnS8o?#^t_w~56H_J zKjG5#`V3MnB+B7OI9BTk(Hj2^#4=dA(BVW5bBE~-Wf?5DLQ4kAH%V}?{3U6(f43kJZ|bB2Gwk_o_gN?XUk~Z)Y+?@?b9ALs#v4m}{jM@VIK?6?CcVV z^e9iE>*;E`mA^!}(&A-?0QCBXwK!8~uXnF7nDJ)Qc~S&kb9+Lw;T$7R`uy>Reg0(R zrSx`HV`8VR%B0PFTVGAD-ONa>l+{VVV@m)iBSAMA2_6L?hef*>+U0w|pRYzlEWJY+ zUpbf^DJlJ5N@0crRVN-^>D!th^P>TsFglqXjD5FWDG#C;d6IR{wwxK=qKeH`&y<@N5Ps3!Nc$K{ zMVmns{)}gM+f~!{hjyE^l516%gM9oOcFDZ3b8P>#rm|9*vKUU<+g(5~BmBdxm$X)U zKGGkE91tT?fXKU&l^s?uwoQ^lBT*}=&r7pcvHKdOn z{1j{OM&22$(LNwKdE3Zt+cuIL*+>SUfNUeViR>j{bENU#N^>)E2z!zj6$KZq9OnKG zK#|Vm4H!s=_bUl@T&;eAj+k+$I37u}zn<*O217~AP9;IJRWxhASxs1OQf75nJ(Mrn ztY1Z_bNGQJQhUM$!e`9`<$E@wa5qo}%GYex&wx&|U-4kFks6hu^xlR#aP={6%2#PR zwNNefoRZ`XwO@f@0Dcz7F!`oTZ}P($z5+8W)%CywD7|4phVjeqh&U0;oUxI;oU!J;nM(V;nP86jy^5COcM0Q zf3OoFNj!+hUf_vHGm`iOuZQl*#H0svJ%KS(g;B;ZbzlKm%WqrrzrM#t&SvxY-)#2% z82Y!L{+i3Igs-d2O86SfEOr|I>pw}&O86?wEPgAJ|G7J&d3YOAd2d6``Z|Rcbo$q~ zGct>R87}|pdwXP->P`JX|N8zaGArR5H%??wrb zg$E9b=;8w$HDF@DN&T|P9m?lT5lA6JkJS2+&QwmAtM@4mC+^WY>5~>w1N!x25fP&H z-OtFIK$ZGQwpVrsBr%@s+xH)y*M}ClR=eEJD3TBgh1*& z!eELGCryMA8;!cOh&G}ZiyS&Ma?HV=^aFZnD-UD}7ae5G)tm?WlA|=h4@sxSP*Zvx zbMSE8oI`sVQ)q?u?V?45GA^^S_QU#7a2@Vf9uyhed&)sqouO3@_hm$>LyqvJu*xHS zIb1rTA9d2;-fZf~1V$=3>U)ulv^kN&1B?5WXxoqO5v;8O8cqz*xK>ZEXkh4#t;$;cQc3g8?Sq4vTq@s?rk16Zi*pNXk@2(!Erk2cFst5I40``c&(?U z;AC<*ZE3pG>uCH<>qhEDE0#~_K04WGYw#)z9gere(di9CJv#ldiLv^Be00*v=^T~#0u%9=y zy*c5`#5rLaWq7iuxrs(CwbwZ-UFJ?R&CkGeM1P1qaYo>gpVN&*JwDSX(Ax-phIJ&F z3KGYE&kMD;KKI5P@PBlnmeI+}0Xh8O#9rzaJBRok#f(_7Wf>WkFrvt_-$N%I<_)aF zyT!)vgdufAqCzX8j`V8rI2hqa1}|kJhWkK6r?zyS#I z|3|yQ#Pvo3?>}5`s9O&6XFd*%!xQIRjtANoda-hZ7fwt&G9dy-Aj-I4BxPjsrqIGn z*KHthe94Yf?+RrA@sdO8yDd2^Q7=0BZ5y(J%sm0>IG&6KEAnZV2pz*{IHf0yE{ZZ) zhGa$_>&G(7&%nCN>yTcoPV^RJ+7NnvpsgS`h_-?z)@g8fZIm_O6yGv$_D)!bXch9U zqg|oje!cL>{?tg6)gjY!tk|68FWI~)ggeQ6e_NQa1MIfw$fnS1omr)5y-B(=o+=)a zx#~=@ShCZkt$Mt7>*?tUZr593T8$EwU|&m1l0V~Q8=h`6PLAJ9UY6`tE!W#p)48|% z4B|Lv`vf`w`x#!scz((2M(U-f96HN6QHO%hiA4T6U_bhd(58jX+Wh}`ilC_TW6s!x zW2)+FE5dh+I@Z*U#mi8|F-w;$ z3G$x;QQay9`B?6l*s6w#CdX;2YKS#fRFpT@Hl#1%hBn2@tLw+5S5a#TH&)jzEv>9? zj8#`wSCoTVP9_jmnw#+G%9{GJm?MPBbNwx<`MW!=HcTk69^E^;}C^N<{rC5d_Lz#Lvo$#Ot!x$qbHWjOHB3&s;t#9d~?D}Y?#xaeHHQtthxe9nlTtsb(GSffT zWon#BVlQrS2WzfqMuf8Kz3j$l^hnPBYu#=tyd>I5__K8^?h;bTm|OG1DAkRskF~fT zMvL9^+*zldMwAcMadWQpivOnTJrjwZ#1e0B>7=4RMm+gDb#70D<=@=m?xCVrB5vF4 zvZdKez5nl{lDKx&o`}n;iH!^UtGtU?ufcE zwJJKAbw9t(WlzP4M7cNCd6^hhP}@_YoT$IBu^PprZ9;n^fwosytR&8Zv_pSFCPe91 zi$o|Go~4yV2g6<`;to~=x}KY~;fGo4Rob@IYK1#^=ETKY+$*C;ALPCg9dVF4AUYzl zm9D;G>OsdH?k>Oo)U1s)B>m=Amz}rAVH!VO?D;7v>g@=3)#WW+Gb!@{eRnaUwvs;?a{z8_$y9wii8nW; zm+ENkAkt?JeL1U_x}=ru_=mHD@WmQ`uJJ`0f9(`6xwLBYmhvr2-79CRx=b~=O{EuK z{r1Gks?Roe_9>??+)kv87m?+!x3J|Wb*dMgShJeuwrwWj&Q^}pM?BN-({202af{V+ zk!@6Z@4D!*9Qtoj45{-vFL-fMRtAx8TIaHbFH#tDhC}+@sGCEXtJih9)D6?A52DV3 z|3~xYzd2RXd{Wg=-%wG9sW8d(moPz=dy^f_VBwP;rZ}1nzuOc?jP?{K(=Cp=BweeG;h zKWvSTisaV2x4M&6ZuIy_*0nP?v}e=5Ni&=1-(~b~Ly6mzb=l5I(IeA-opo7swEi5K zMocB{hOEonk8in`=?*}`=6h>- zv|OcP8uKXHq1?81wXtAJ-P$y_PNdJzGRI=;0oHT*x2I_o_=(oBCdkT2idO*Qu7o)Zv+`ES96b z*QFZMx2XPYYDH%IC2Cdr#mt|Yld2AMJBUW3m{hl|(#ylwsXKIrwXE-5+{8lfqsORaC+roMD47qQuD zwOh%lJNi2H+tu4j$bs}vJ=ANr`?k8z5VA{N%$`>=Q|<26){;A8{^TrG*P#X%tGePU zHN@?FyS*yjPP10JdbfpE47Wsmk6iJg6P+Ka*r~2xos*T_KB-;3(ksV3!p&V;)lS^h zh<8@-yt}hE%~+dGJ*_G_HI0Z*X`kHDo7ObWu;cFPy>016l0VeV@pyJ=o+eh{U)VYt;*yT@%L-kjNhb0Pv9Z@|!7o>34eyNKt zO0m24xi#Fix2AB{KBswZPoepH5_kL4Yj}a6J{u7sf;zCW{ldppf45Do+Vh24RXp{| zc(d-CE+^KWHCjFE6sx;hX#dmP-md!5lDG5Capg};oKi4F4XIr5qUK%db>ca@UisuV z`o}$J;(d!|{bYqZ_S9L03n!M0o|JpLdxRRY_hM>ir@KAQ6*i?(v-|GlSnl7oR4q(b zM`mWJg*&cLSFCj_$85;jpq`CH(<9NN4sefXnyHS|8#J{k63wGXTep{|s12%k{xxdD zIz3-)(wVQ;>deJD^M#kWOl`YHed^)Oy5N7j%oRHGp_loQ&b+5HQ-&1uJ%V=ZKtmGVhUB;sM;cK zx_aHAAlyiGf4hqN?aoxnPTZKKZlYEG#YlPyl{~SEw{-9IqG2?tJ*!!}J+&jXM28Qh zDs4{@v29q*bKf_;c$98f&2iM08a*!3UftZhd2{>ZQAGY!OWM+lbZALrx4J2^TWw#r z_vIy@&VP}XW~z~v{p6M_rd^@_8R^=Y`}3tVQU||RwwmH3bLcrG^Gnq7Vl^PW2>wZ*;u13hUCE*Nz;bTxL&U?Fc^>ZL zw$Y}6^7k$0FnzWUg((qe^W9ETZ_!LI^x=KPEz7xiZ}iz+<{m}a_;POf8+|I(<14q7 zsKjqutn?Af8Y|yf<=|dzTkdFwb8jK#&gul9jae(^Xg3%J9X>y%$&NB zaXEi1r;ikO2!C=uC6|e*?qJ5LPZ;u+MDi{}&ZRE;ag5vcZa+RcT^-}D|69MVU6k1x zi#$Qmx9_a0v;Es*yYkL|I>y&7jv#=)-+d ze>PJ2wwSw@gzf6*?xkIKS5B5&MNvE4t)tmh9qgtPV(5)&jwW98_VwpYeMb}P=<44__)<;p>K}9GYuS9Z ziKMDOHScAR#UC^IW0LvMSwoAepY_dAeLA>U4RF)l$tCV`|;p-Oyhg0*5%Fa;H9+IHuEC&!n%%0>d|N>A}PfQ{y^sb(g9;TKA~_d$~Xj+p%)`QyVsJ zosqk73y+d}nzRqE+rP`5%m4{$58*=swk~fgifrB-@K$9ku#{ zY1HDrIh>xxAE&y*RKpI{8QtNQ@P9Oeeb%4{<68rYc~-r484vTf2hi4^wro`U^9J5o z9!4j@i2CIKTI$u&+nDiY9Ta;8@G5rmGLHW}19-~5c^Nn4PXl<$p4_gUZ`r;1Z;doo z{}J1kHP1~`-|xqR^XGcR{CU5eT_w>G`(Htn?Ts8{ukY8XK8o$0`SEmj2z{s@_lwQ= zL=EoXW9@}HLjI*AXQLiFU(wikF4jeiRBXDR>)q3@cvSB5*Eih9L+1-^>V*`)zl&`H zGdJ^HE$eC>h3}E9w|rUL15ZbH@IbqsWx1oSZ`jDfeyHvIm}2tJu{|`_)eb!iUDT*I z;venTrG^x%*_pJ@EZ*#%P8Hr;rhRwSfUYH~Ge-NK>FV)*#p>4{e70ZlRd2cDCK2Py zI#6#MkfUxOUlH4@#MadDb1Hgu885Uy(FULP#XqG< znD}2`#)E15fDZNfx*ckl+N)0OqSJm~Os%PZ<7i2Bcck*99C7t3>CW5k&QtxjeM+|$ zs^6aY=VL0e)Wo*e)Ihh`Jy%yKPE|v8sDZSD?ot;lbJNFcP~Qyby3d`zeB$I+-Cgr? zcdjA>rk?-48q5pG*R|~Bw!t*!%hYoXde8UE{fpJJ9=wC#GakH?;L{#_fZ!tyyY=4k z;r(e9eO&Fod(y^|?F+Wk-gd|PZu`CWx@oy?nwwGNt#6g7J9q9<{V8P0Nab$k&udBj zjkO$>e;Mp{xV3D4yXxyLDtbJms=D2uFj;+AuZNaDmO_^Sb;ZC=ito-^K197VI68*p z-Kn;{O(&WiYD}j3*J_&kE-SgfeVK)x|C<+^-6MX+@B#iPQ-ij>rTTR=tJ&`0TGiI* zcF0kRk5l}Q4Bn&f)!rTyof1(`w9w-CghTta+m^Y5$gIJjeoBjRy80VUU{|iosir+*rn+KXj`|?lp|(=`A*Gj7`cbqqS9LJQ zM^PTJFV}Lg{CE(Z%Xojgw@zQbeKe5wyXy8xS9^Q=Mtv5o)$7BiA-q{t7e*`9C2REg z>b*Li99|gg@`n4CS|0!8^v>DSR;dA%s&8}>pNZbC;aK=_n!7{YSx;AXG{PtINPTf& z*C`jN)#>B2)F5~GCp3+!osrJB)JJrytJFg^ylO1gGt^gu-OSm~t*RozziPM>E=i+R zfDV!|zQ5X|<=>ps z_ir_Pa{k32YBS|tuH!cRd{A-wQgwaHHn-i)$Zl58QHwW4c3ekNI<=I?(%i}u)b~jP z4ZhDw*(LRE4&$##+j!P?hvs{Vv~3`5w4`qz+(Ghxc|L2qd~kFcIr0m&O})HUk7ln~ z7pBokj$(I(BZ6B! z_&LEr+djU;9m|*9*J=@O4q-QcRI4RiL3aut*0P%?s2>k5j!tGbU#a>2Hl$7MttB^8 zXAFwbwX^CxpSFPPI`!lbH#0SQ^x#x?3ej)V{Ld2q*B<}FgJSCWHJNG$9q6B5le1FQ zcBuzbXcAwOlc63U@S8O`>fw|Qb^n^2P3obPoJ;ATJ!vnw^7rTKGt}?*r%7hByS!Qb zA|8;NBdPVr%5WWQX_4z!;c%J@v`V(Y3)%?Rcj^WSJ$UnL5>MxEvIR4(G_Nuen z*HNeOfx9nVaM1E`9uN1chw>ijU5$S{l(%&BEF@Lk={e;Ya>^YZ+%vd%+CsH|rRu+< zJ^S97`hRtn8++^8nI-i9yqUb8rZWdgd*(d7|F~-??>U}0Pd_5~)zD0e9v#px4QBPP zXq7h*`9_cY%HZOEsr`77dFDLs|J#RVK0%qMG~ZK0JJQ^D)To%6*YRoM4=osJiiDgW zbI(yjVya#j(?x#TIkY)WSG8?%byy`GbJA6x;`N)~(GAp_^VBocpdB04b54%BwUw?l z7j~!-?(oyfo+yvsck_K`&A;>ZqWR}-qFw3ei0V_BT{W+y{k(#fIV2#emh4gc6}!8Z zss?=^Q4L+{)EzIor(GV;eyf6aNXmUle>U9h;Sm$N@&|yof zJDg~A{&l+eF7JRCU2c^qikv<bqN;jq)x4?&^XY?ys4|k!N{xKk z*&XGFk$2M_dek}R|He&vj}ILapL)_ob{Re8tDuL2A&(!w?RH%rCF<*NdTdFz;rvwb zJ3UHd#u(qMCqBI7i}crH^3>>M`h)CruSs3;+X$aN9&e#&?At{b!DEi)g2aEkR{csp z8+yTUJJaGj_0O)IJEIZmx~EdP>sJ2%uj{;r$LP8L{%OhoMt^!i(ES+-_bYylkh+6j zIGm|&Qk@4(9NX|TkF|T~dPJ?RoRoV7-Ntp%qcXngh+gx{&GWaoLwI8t{o#X~=n+Bv z4)vbXMqT~IS`LVTHwKjI8a_*Ad= z-=}AnI#WDz<9*uD+ue!8vuOqI54!Zzw@X*>T77S?uGRWpC;GKYqq`>F8Km$9W6I(D zF-FbrD5b0Db6(Jo#?|mP?^s^l$wuG2nnk?Qi>~RaHn#IcFg-4$j~8+msY_`K$B&6# zQ(dpB57%Ypz8oFB|EKOWb!}Adm1z~)%WJ<%)sF#G>b^TYOYd~osam@3uDU1p7E+x) zm7YBBra{HGj(vBl#mo}+Z-%vL#^xER`Xj9qJ6m^CTC8@orh8K8k#CNA#_8C}4#W>bsR&^>N@_Ep!bA^OhovF+rqXms2_b>22YkyO6VQmK5Ou150*A2ev6 z-Lk`E^jgHH4y8YI)}zr4Pvx$n+%YS%XEvQPf2SH9Q$^dbi@HI?gcFi zqN5LRC%a?ccF(J5pMOp6{PJA-TrlBmmE&fr&mHpb-`B?6&QD*7)8#Oo1Xg5b&78Sf z9kpX8J=5q%Cxea!?&K%A@WE($u6l?rrq~pVsO@oDFT9mBIW(^H!Pdxy@y&i(uSx(UNqY%W{g8e}_dxHQ&na{7O5RRA);n|ge9GOWpIJTD zn>SjWEBPGzXm2-j;e53{LT3~=(>;m0_9E($cSaG%Ys-0i`9Pm-s&+S>;4dK3Bl=eR zfj)aCyJx$3pH!8o96l|b+@c-U8 zFKH@WQeWFpT~ijTuBRvW4Gqp&XBQ5idcp}As(8n z!ltsN6%PG1CN3^rQgwc5Wm$ENQ`%HT??^3fu5?PXXP4I0Q(26k(9gH55 zHP^(PvRHkk)6lefdVM3k66MUDkyk)(Zxu9F*G^j*Yb-mvzMNj_BI?wtiY4ct!7rXQ z&0b#7SX0*ER57PhN^L*CqOr*-E3cee!G0hUNI^r>Tz=td_TuwM{M51~RTbrgsqIeP z8O@b*t5;Vzb$Mlt^ghA-gv@3qHI*&*+Nj?hbEef+$Fv1xOL^tg`ufIlw2m9)nRhno~nvFmep1`mHh6AZon-1T)fKj zAo-6}F%$Lj>I#YsZep?iEYY9yojUGGdLvKU+el9ItSxI?y2M#LtD>x_xv?U>ewpXxuvE0y}IhUQV#A0>Qs(y-y9lwPQ}V<3J2|z?DB*FA|0f^fOJ;GbTg|Z zT79A9D($q{&9Q*jPUn~|ubj_;$hLXmuY0S!a+YoZQOA{LkYUvH(uD5kUT>hDt8XL$ z#SkE@6mX?lpbj-HuW9w!MvG~k-FWj8Eg8Eol%~Tpj>|qXM zjzta=ddZU}1nFS%IrV6UmyGk06TM`-mz+ci{7da$QdQRI{O5CM;zUS$Z;rG%6-%7b z<*~BGH5H}x5)x&4!0M=~o7=qDn;Xi?y;(tzdfg8rUMI7FUGLS-(fqO6|zNGlC>jO#%nQ^4J^2lXE}yEz!0oW-ja}!@$W1M z$<_cpzjK=sCOe9TSbe!uT3=HR|HDc)gJ;gUG5Sb|9o;a~9n>uLl5T%#Db3#`2J?Eh9^5sj7Bp z)~AqkXoxYXp=nM%-Aa0^+BlLqOApy4&5g8#*EH99T`R+vhIOf)7P!@{_T=%TxU{*h znPx#6Wz=F`Pcf@!*HzL4J*Q$>b9G}yxi^qcZ=m_Oyr4dpRwpk?C|>C$?bs?^&JL%Y zLvyTx7EgM4+pKN5xzkoUbu^1{U{U{(p=B#|{PBY4%{Qf`ytr4-ZkR)_NbC7~D!t-O zQgSQmmePV=cXq`JtepPfudS%%^|F-Tb*`)DNYc9&M-Sn$@``fNNv3hk@Zde0R~E`s zwAB#58IswRXIIct)Ku0;>u+`)EnqwgQ{11vgvqov%&mwuH=J2fSw=etZ>3|SbknOm zH+XWJXoFM11EyAMaHtFEZ$q;=Aa6s(Ho}D3i4c@ zv-pharPJ!ltIO&zOvO7qXYsmNURgkriY4XMkcTttAWJ3Z$=CU&)wyM>sG-$*f1^E5 zZ9an*cD??xRBFczT0e=&_xcjAU5j(eR&#l7eHpDIOPy+747jzlAL6zxo>A5`OMlLH z8s_k-I;*1Ashir|*hu|K&6AccKD~yj&{8~iMOni<4w0tS(|8e@)kKkyS5FdkD4kV7 z`vZzf8mu%i&8?IkbSMb)n$2-lUFXG>?7zG%hBsBv295Se2$HRZr(2BG*^yc=5ub!J8-bQc*pvoOZYr+Z@C^ zgHl|?DrnP1z7@xk^y$qtHJ;0xR?p%fq&f}W*sAt+pcD!rn?l~_@D`zoH zt6~*RJe|^xL?lzI{1B9;(%@TC)u@LS4M=aOm<2!wCVV57F2)R?wwlfu~kN;lEqNu$@fSYA;>;lvx4l^MLwHJO^#db>me#uLqj zhLKh~63iwTcFOY_J+;23hNdame^cB~=XTLJ=L*cgJ3KxLa$Yv5AoFgWi)9l<3bkQ; zJ|yikGN6AP+fvtD+tj?6w+DI}V;S6~xz&qlv*}G0UKH}VyR5OI6cZkEvemLTj8Qhx zw$sbKeWG`GFs7W?&6e?6J?~OzV@SggQ&pn9vFw^;KqdIin-~%-sjeH(GIZ>6yJ*g+rcIAHN*tG6_g@VnbA7(}Z2AfouO_Tg zuWjB`z+;y-PP7PcIO?9yrEf@Cy~#T(FV4pC7SZ=qbshC=x9m85(NGqn<77esMSx!K zyN5G-6y3*>=JkKmYKm|(eiMbCNWDTGp{=C8^NY$>BEGcSs_U$*)~%zgp{5!eh=lsp zb>!#7zDTqzA*jkL=akjaLUh|<-V>a+B#k(QfalOJ-{BwSY<_8-2mMdfd)U+~0K9g% z#};ws0**Waq*B0N8q!?A`-GI@&@bqTBL_1`oUh(PFyb|1L_XlZ45h36$Rsh>!q->mV(_dTY#%?qBReBKw5@q%ZP&l^w1dzSFbl{D4q%AjAg z8~8zaweXRxJCn(57M=}~CX)%T{o0rLPBNJ(;@N?cCX)$wqXWs#FO$i{7{>Gwam-Aj zB%VXUF<7e*0{mKm@Ealm$4E+cU7E};@J#c0llEVc@GO=znO{)8(wCXE|27HF=5LY7 zzZQ;vFwIe$ex0mMn4d0}{_CkOb3`y{~c8xsAVzV1H|G{mq3b_FOp zOjxLc;$aiZH5x}||3i!lK>ou6{6i|Dab(8$e1QBn4GbSL zxzdBw_9X)AebRD)|L{qk4F5Cejsm!2m1$EEn)$v@0z}J{v%JAHv%fLF2oNpPe8`;W z^8un|nh%+QrU6C4W)@v3r4RdDegi!O0qKS%572jE5&Q*#G&e!!^L|CZe)PLG`G>dw zeF4=J2rTePfFBBpjuWr6bV;U0Q!*`ZxT88`tlwYnA$_H_2k)^iT37626nT%fnlUJ4jDL{8DTKGSTp`RKKDl< z{cTiaJ~bVY2MDF4;MtZCtZd9C*Qz^CV7tFmcp#2=S0>}_klpWgNhwZlmFnH%WZ&6dcKK{CrPu~s zIL9M-CnMy}6DlzRuIR?tO+00S8VYO;w4B`28dOkVE6{wl{1e4;2<4vMD71@BtMUNf zkQs<%ZEZznb-pK+h}&C{SuaGFiCa@fMB+ae%AG#@)>dR-zm|avTEIpD!(G|}yEV4A z5?gbnsEs z8x1Ftt!|KTA7g6G0X#uSdT849{wZc2XlyEcRiJNE{;eVcT}81A2%klq{6-05-%P3I zEB#Q^-DK1iKOoTWoD~jy03{Kp7!duzn-tqGVH+3pgRij!@J`XJoK?Zlj5sB}*&c$A zea9@dt%^8H?OIPslhMA2Q-S88Ekv@LLL^%dTH*^T4+<&|3M#h+q0dK3`#Ge65sXITyIrC9^N+aHX|xx+`g!;fy}w1GcH9UE~DNb6=#Pi%G@ZAU#U!|QcPxgUZ3&JR^{MGSe^uzA7Y-5xLUIh7r*Ft(Ca%L@p)^0I3FCB_vNG za$}_3#OR6kKhd(tNl;n<`1PqEEdV^gG`0i~jiwt4K(v^RD2OB1X6hCIZZ$4h0Jy`D zN&w+4(f|loc^Z(b$T9{4{?w2b0xmM{T>uD&dg72<IIIH|LrWx(FQs??;?P7-bk6M0!*P z%|K)NBDBW$`XYG!B;(>maIx>HMZVD2Q8qOB^|<`%nOAbX3^H#QD@y`g2qfgvo+23uiBKprk4PxH;hXu$*( zQfrHh>buS8E`osRMoup_S9_E!$TVyA!q~8AUd4s3l;+Lg870oZlsZQG_C_?PST-$tHmSo9G$tMDWH8d6@CXq+x7aRDwjqy>O$45}TxC}D0zfSGG(BO1eu&uu<^iIK6fM}D zw@3@gEnUBrkKEssVKCug4b`M zhu)Vd@>5AEumOikr}TAJIpg@A?8K3AG~x4*GW5vnGPn}!frg&hkM8_iwx&QVdSsyN zDy`yVM#I5$1p>q1TOz?8=p+*KpyxyGPC^`FtA9fph;XAYvss>$Vg8z=QD;IR#B844 zPSfs4>WKc|%9!G`><&JYf~pUDP-*js${_)jHY2HgHmDM+{?&s@n@3a*3#haiN#(mi zl~C316wl>hjqAYXc=+f zPYf-%TeD?_?A9RWcSg+EIPmWcEh7%xlR8^g$Oy;mh!r^GEsrKy<5woE_4~`jiE5aa z`^Yke$qIBoa6Dw!C(G=rA;u09t=I#E7~3jFZcH%Nu9nOw@L|`{!!E>b&v9ZIwj3dr zeP1l@*X8Ftk$dl$)x3MZ`o?BA^^{lB4~L*j=|@zjizv?mFRMUt#Q z<4xreQrQ%EGW}23015PP3W`yeNIt)ZIz`_jlJ4)sW;0 zFyRS`XDo716JqQaV!{5Wc{YY^(QF=9?|u0-0lQr`XK$zF*wp3_MyMOngIb%XFVv23 z1Bz{4Qam*98kA+SxD!W;-52;@Nte5TZMX`|Ze z3>%>W8YTz_%!oMiZ6or9rC3tad=UJ)`G7Duv{euYrm$9l2LicOzzt$Z@>Z1#2Q-AV z%06n-D7oiyujz5y12%8yC;=0mAbO(&Ib2wTjFNMwc>2mErQiUp5E8AE7qwh1*Gt!! zYo>fa+_7msPn!Q3lwS}ORp9e`C|Ij7SSzsXTs+0Ay;ah%t_4qr@bG?zhcWV~>&*mV z0~`{-NvE}!f~PfbgJ)ypQ8)QK4GG|+`C>w9L&!XxB`Qvr z)G&gOEd{h&16(Sk(1`^C!4%d$@IW9>EWpJg+@**NpDuHS0~$hhUTJcEJ4(_pBWxbe znS5RASU)x=1>Nhxpo6XnJ?OM~yig~dA)#*blGgQ+fNj%7TY;o~C{Xx1O9>bkGjbxB1rH#TOM>mV||b4 z_>-ir15Qx>DkT)`fL{xV-X;z14ImLrVJ!p?1ahzg?=zM((6w&Z-rz0afQFFy2^Y?V zvL^AyIN2&{^M^c7L0wx6(;w|#R4&K;eb$^i8h(3{&X)EL{o*zldG;1<(W=!`eXGuMM z{zeAE=rv`$n}j!nG#}msJ73;X(nMtNLKs!HUj);9wk2ESqG7SLj;)2Z0iu9uz=xQ( zr1Aid5EAbnc!fg#7@rj|-C{+4hR+I!RNrN&ycPFZ6O&J132dPmye1cQOq9S$8tB za2tJr<7&D|Avv(@0`Z<-lFT;vhMw6#8^jU`^3c+dCp#gHv~^uC=A*l*n{5_^JZzx3 z@3t#Era<@GyrFX+nD9oRH}@e2H6bU6d2-IiTLmF=-)%D9?va#Z0{B@&%ZLNNU}(Xs z8(UV$=?bxeu^KXAA1@<+Ou`H>RJ@LAh|;Hpj&26s?h?B`^_pEZq$3X#>6k4-j6GS5 zoRna!T`ieW;KTgX!+d48=LE6r6iLalORdQ!#Mm>$$g>iRwI#t=TO8=gEWyl)Mj-E7 zm}iR&n+}VmLHWR}HiFQ8DF3kn=3_n_70>FFBF=GFH&VTwN#g`Y@DjK|X7Fgh|0!oQ?|Hc)`a$j&14 zTn2&IeuQmR!2^NZ55WCIc=8LMZ^R;)5ppg&NQ4|NscAk4e%*XP7#!Lv2n17DtH1++ z+$!LczqM7z3kNiWvwXfu+^kk<>K>cSpW+B~8%_L; zlZ++FE@#FH2Q-A-ffWnOQc2l}7iG+RBx#soc0JFn5#*0LLFYoI34Qvt|^ zgpgCm?b0g`CiIRi96a|44+a79sGEEcKms_;9lNdSx1!=PNev?iPfGzc1rQfD^cz@% z_mdC^rm#o@4+QcM0DeXE@n!tl(EG{fgaaBvhCr(H;800%MIG`qrjM{3FKNhT3q=!z zg-r{;Ivp(>xQYo0X%yircXWL)CE4|X%^P}s0498U(7QfB4r)TK4^V`g6SAZsnI$%F zs3l;k5-)g`AO|%eC)W#SdSQ8`q){g~4t$-^DE@MCJ+^vDnXOgurIHd`r@+DT{b*(b z#!D|6=JPd${1cDfnVD`D|>mi*K7Z)MsGYB)UDHAqO=fJ{ux_In?+p zI1Pg5AmLHYvi@;oP%-JT0JXswGMODMf=BmY1bB}3jTjO~1{ISY6i^$CAx4}gg3pqa zj;DaNMrU(yrb0bL7|&D)r>{(i1-*)TP{OkpaG@yVMWs1(_R0|sm=-cc(BBo-KR!!7 zAV!69s6hzym&902v?CV6{@qrh9yD_+f!BO%D;tCZ_EIZtYeO1dB@OWh_=NZ+Lff3s zBO_#FA8$r@u$LgK#yDr$usAYMU=EAWf@!2bP4V9E+~7wH(07dJqj5Acjtq=QdJ2Rk zP)Z>Tb!ZfYEObCzNT6RKO}SQ5VgZD6mD3mubkqY=*pdt$2;}YtzD4x$y4M&Q)Z2vv z8bX%jM}_4{N!bWj{E68)%rMk@T8axWC_1!{W$5jp4S(3Uom%IT!*_ zH>6vh70WOTi3RX0V{}NjpdOgQS`QuwzVSwDVn^V7Z8Nb=c30UvA6Pfg{q|@vtHcmIm)Z%e+E6A4-dna^i@wlc$8)3n+}9W zi4hPUrRg6KJ|Zr_-x+u113o29ATGdT$M|i{k0W=6P>B(+xf>&L8+=BL1olWakc$mm&jlvl#j0`ToZqj5Vvo^rIu zkRd6(oB;T^Ar-zaaQ-nKH*o>B3W@G`-1vo(+3xcJer8AofPO1W0AG-XQ@lO9?q@Re zZZJcTRP2(>?cvdj5NSAgrud>A5+pl6^3si;4clS5b!}m zDgk`lkO~1`7Lrzg%xi{kA>iAFG#_y7iJm#!kHGgET5f!=;P)h@5CHrtfekoKrcLUw zk#S_E3y}}rz{?UDk--GQ#&~A=pW9?aV`MWAFa|jNZd*VMaAvbdEYr@Fh43axnPv|= zreWzoIPU| zrXeQK>rC@q>!E|i!6PK4-5MYkGP*RvT81TyNSJIeH4q6i!l7oU7NJS#+ zx4B4NFvgw~b?=&%1pHyMgjochJtBs~8F;UuWyFD@F6>pVXotmU!2W6Wl zmEPp%M_1n_izZ~7Wxl8>>p`8(lS*&EhpB528Lg7?z2NH5E0maUTrDa6qGH>ypGeUI zhGmY;GE#P=$4DCHDw`+8SsU{B+U5#z)M=t*mZaP``h~tBUpG5LI4UF!xro5t8!T)& zhV2Nm`3&Ck+4ZP3^jO@k=}~QO*>(HVe&73&?{W$qTSoU%TNdnYGS1+yH-$N)N;q)J z2)PKoTUhRwG^`tKo{;J9cT#I2NyBWidC2V{-_WwT zLPEfkD9^YDITWyto&<_no~pk_r6>TI4=XI-c| zn@>3n!SC5`6h&JlO{I0S!3n;=d6AUwl$5R}>@kC)`-R2zL`?_^yInY*OfGDIT=oo- zG;F=Gd1z$`*-P16A#=;IqGW=kE2ogk`U!Vf|(EP|t*Hw`{JEG5=3d(ocdUx#iyo=h5bBG2n1q zgB~U=10 zY4e8aw3$M5mdlf)^Caa+1gSr;|aIHmPG1;doDNt&jZ6Y-e1d9Fw8vn3GO?CJZq%^zVS8>85H~u5|kXJWcZOvKw~1N8Q6_1~5ferA-G!YQ6jm-An|xt-WOjl) z9t)AbOStcql$XwL1P_vGOe+vvmO%6U;vvYo+gOkf2=Vk%_k)ftUlXBVp|Ld|5IQwq zGNsT!`;Vafgn9Iu;}7T9)uBt>|Z$xcLn9MgjngZ0)< z2-aIW;oJ04Xbv+9hlxT>L7l?l28ce2BR)rI4UI#39)nWW`+NL(mH|d zlJdJ9g@JVw6>Chz0ze3$jRat#tb(MnRvB6OfDpis`+*aMsGvBYz&XN;l|v+@JtN@dhO`iHhmfL9lLI_$geSr4 zCgkoHD&1iKo+So*jL0oCEem`f8@3HKh7bZcJxm9LW{(j$-;Ppy z^uUg>Mrl4^^N}7i-Nyk!5Q`5+M^M%r$jUad7676ZENf0kn-+w%X-+)YrocWnXh$*Z zSR>7(w^?p%MJCabVq?hy>1EA|%(8@lD2^ld%S2XWU?{h*IAFGx`t6-j0>d*+%oPD9 znq6YdMi+%_@5W2xvrS*;0ZuaF=K?}JjT%5-_FUWa7ewXJkh*Z zQvPf2+XN#5dJ;BPB8!CG)(TOR-rO#OKA+b(iG=r83z@A&QFjntEzo7nQT#zA?2e!neB*2)_b%mV(E zZx$eWguV&`v+gsN<^lfBkmmkNAUc691xAOEFgwDS%{FzPn3EzR>Be?k9GU(?OmX_Y ztK!HFG^{jup?17Pv#yWKbRl~6k*hMSR390bt?S!HLL(g2*V$$^PPPGwWw!9dGF!)S z;t2E;`453`q3QgjNCz)L~Z-`w%mW8(euzX<_psp$p#I4N~ zHjUUkA>H|zvyeHA4CPl0PHmWPW=ZU_Lf|EamJtWWY!POJEh}{6 zVo!T~P)5a`grlC%b7G(qP`26_PQT++aI2vOpMKf(wD*D)gWh{kgg!4Rg)rcL!@W47 zP6iw(ByV$w+)$sA7 zsSxlHA$cu8?is^47w`{;6!=>P+vN~>pQL02;Fq%8QjY`P(9bj3(}>*B{XHr%0%mtJ z&2BlAzG9RX94pH9>jPPfUJ_-HNxQYDMbobR3|BJQryA??0XK_4nl=H^1a44%964yF zClP>W8W+w5Ol)KD*7c8~{~cpT9^m_iR0!ypW|soO7@BqVwZI2(fF>gIg7JSTAZ*io zwu=fxf3dM64{$_ZICdf6dEzw^wZ0YZfIYOJ0ZtSvG#^ZZuR<0+#8e;C^gKYQOb93l zBog30)9gIJR1+6PfcqO#9^fiNDncL~Zn`(Hafpe17x;Dpw)?JmDXfcLYJvQFL?t=r zr50rFHFo3y!e5%t?l+8$!+lEt4>SF?2oO#rQ5Us_bkaqwFb+yXt{pKf7fGn_>IVFM z6FzgU5cms8`RKMTQ*{(QETyT!0M>{PCZH>6!95Q2M z%fT8<8F@s@AsS5}bf`v0#KFJNcOhUxXYLK_%)O>F;V<&+-WJ<3v;&Qx%Luds^+N6^ z5RxsX$$5ZnhExdX%PvCTjx+(B2Y9R@6$1Je1j77JG8ca!p5cuXrXWNQ)6ieAfoTY6 zh-aGZ7s$u7qIaFhAXdpUwoc6l12D%BAMAim&1Wm!CXIR9?{2{N4XF?iR#3lw9u@(g zn+QOIHK(l<(`$(t9|32B1=B8_9svDXfsH$sln+F3Pe&M=Hzel3f@O(}0K~FHy8%Eb z4Y~8fpjs?0CA*RyVZd8v++P5Q>LI2EYZV4-mD(MF-hWSY^%x>x3Yi2U2cbib0`zMI zc2=`xj$0@x4+`LVL(7N*HyK)RLth|e;2{g_#@-+-cN#HcL zk(AT{q8dg1wpQB)$bQ4f9vcTnMP5PddbaS8=FOJHzDQE`CUC8x1x4HSLS8PxO!B#i zq41rW>;!J}hQzAPLY~?eSS2vux69;CI&Ztwb4$QGHgAYduwcy~2LfWvprH&1rL>o_ zdjiYJak6%hT`wiG%jONS3oKZY$Sy!ENn{rwl!n-~UXEc`nB!O>;Pr+y7w{HCDg@ji zB=6*c-0g;OF5unW7;XOq?I?g9KR2?90HK^7L;^xH+ffil?oPihV4@wtCze4w@?pm> zjI0HKP)@-Q2+iKX2f4fax`2sx1W!3ZJLbTS#EQYUj9!-j>ynhh0C2iIOQw|uaMTd5 zBfQ>2?lGYfBj5qj0FTk`Jt#d?9%WL$6bQ^3=sqHB$$yvF^&D~^Nq z^#MLV@LYL}NwdJS>yUX{h^!3wxP!dPnh}`-Au{7*g0m0ywE*8PG+h~)LE;OpZ2!O$ zXg);-V5PL47D7Nc#0wVW&<(^0xWx2GJ|KD|WL-t?&Nm&N2e`cK4@9!v@TBzqvnC+&0DW}}q3-FyUVS>uqRV}C3xnzc8@M)6bGxq&aDr*w zT)<32Due~_Gu>dof{7AKL;{>_NQK1$eSM%AjZaleRGQ{#5RoFkag`~F#rbfwg%Xbz#_N@ zN=Op)U}EB$z^(~^A_TxbpM;o&pGX)i{Jn{ZqVdwpQ%r9cApq|6N%nxs5Kp1ksfW;6 zU4Ey*s6QE_0zCxolajNbl}8wsJiwz2sSwZ?6xj4Y(9u$>r_Gqn8?xyE3yh(V1cWiP z+5tjoNN~VC=&%r7=+-`_xp_bT8Av!S$uJBu5d}Wf>+q|SR z_&qu>)rvr`^~ga@$b~ajIk=BPsX3V?HgBjUVCw8<335;qV#$ZHZhV}uegOZ&&@$q{ znCrtHQrfa;wy`H=i22%xre7%rEIT${0i%L@QfJEwdBY65oSm|^k?-;XbBN6pvONs4 z1X_mu+jFAo-`nE(wE{aeY)wlCdd{R+N&2>c%^NZuf(6@K>LfsHZ)r&Ygwl}KG>bh~ z`*tP0YO{Gm>tc5yHR}_M$C#AdojUz#ob} z{yRVP=Q7-p!MDTyDl9{Wddforbbl%GS@Hp47+F6m5VNQUrZDTl1A%Nk@R6by){hEW zf1t2rC%690082i&VHjCIK43lSfho*-@IWA24?NGZetgjSTw!TRZvCnNOFp<^7+Ieg zupafm6lOhmAdsyG{()tE$hRLi2+JMGt=|=3$p<$Kqi^g#65IozBDliL2M;8&`M?iZ z=7)UW@-AU{H@W$523YdJ4a3O%CxhmrBDliL2M;8&`M{r9=7)T7?|otU-T_I+?LkuH zv*ZK9Ff#x7p!ui>t}ye#1Bq-t@Cl+A1GgX;`oo1~PIB{S1z7UI4a3O%SAyoFBDliL z2M;8&`M~E|<}V1EUnne45i)C{=tsgzOJdS%a+^0~=?Ss~mL41vH~8nW{42fa2+R*Q zZ-~YqOF-jrxyKmq-)8{U8d4EpgOI$-M&z1(Mtk{#_!)+!0I=SW763vZi!X>H=Zg=V znH%I4qhCl$TMEEG8`50Bw}j+bkKDE9m7KY@^;f5Qluk)G#B81sQI9f9Qri3iE)kOV zUNCZQFRudi*E)gM8PY<)n}p=mMeff+RZi3E&gYVG#5&#w3+yZD5U1%~XKPBvNbhf* zj2k(kJmaW%j+8F;D*{#+Qa)gPkFsoc{8`%kfuv;V`Uo=PmB&uRiz3LZ@`>9c$h_zi zZ;T*wOp2-A5kaQOC*Br8rqd^09YF?;C++t{c8T-u@IAUdg3LWW@uCPa_xr@{5oCVr z6K{+l^E;o|5kcljpLkmYndf}s)e&S8I{6-nSl`PRN^fj29hC=&Xr&`5AOe>{1Mq4S z?nS;-4^0!9h!2|YlD_?H^M)UmErB72k#7IP}@~{R* zkc1sP?Rp`i?V-;34;3v_)tR|7YD{H z!}5W9k`JCdBP$~gTxDqE;=q`&SUzx1^1<^XBP$~ge5;|2ivwfsWBI^6$p_DyMpi}~ z_$xyj7YFW17FM^*Ws>7z28?Bn{SSce({vSijhyx!e6I__OmxTWdN$DvqpkJ*)hP^*)Lv+-L9vcTvGqj92 zurDk40*tMXOz;(X=vg7WA}MXQ0ACf7x3fa-O`j3)-ENGMF-cHE0W>65489z&Pegn! zDVYZNFGDH-{7OikwUY4@S#w>pfh+`EU`TTT&o!h%z%n6)i+}KJPtzYIB~t;P7m`;I zx%YiW-$oCu7s4fyk}SY$3~3JFwL%KFt3gU*reYyrbB`6zmC|y*B49<274xJNfkxH? z7WPx7QaZt}2sq{6tXL3MF&LOZjrm~}gRhwk7kfrZN^Jx@sz+0U z6$`>D22BlC%nz&hT}+)5Rx$WS%s^?#5J{k!K^TR3z+Ze1k zC#>RkY2$xf@jo{8KX%S{><;NZ>MZYv`Vml;{v`bvtXL3MG1!mW4l9EQitF zIS0H#NM0}@x6LpX0`4@V1uzY1P-6i!zGI9i0)!6MSP)0!Zzz%9nAKnp{T zgK5H@Zj=SjK{gLP4&BijFv;ek5P`KwZxbbt7!wNtzcQpEKu6{zFN%=sCDf3%K>SNa zRsrBQhO__>0;StUtS>$gkppEvI9yU{AmEdRv;gprLh`If?n|E$PC*Ls(+o=i;Nylg z7Z3tH>yh)t2cin%(~Ycrz^4sqAs_^@`209>zW9Z(8tKnO#;ua_VF37Eq0v_tTjR() zVwC1V{9B295R7!K6mB&2iU6U9KK0Wk=D!)a6%b9Va=wzcX5Aa+=Dg|s2 zQj~sAJcR!vfre%vMR!a$JY(a)1x9=xpx>HBXpL|BA_zsAF9OPq@Zc{RwRu7&BCx;+ z`epMeabzG{IV~xHxd4SVJs4o~&@Ex`R|^H1TKWgHK})O$Z8i^S8~&|=sBJ?6OwfXW z40}{!^N_YP z|H+6i0Gw^aF93u+ zgg_QQC&W2{$$h=ZxYo!*kD0LeyA*wroMpIpKi~91A>axj(eJH07kG=%yihiZ1V9+L z=|TuFv0`v<9;}!jRxxU(h5IvDu^_Bs(4WDI`C%1<{(M&KdEPe_@P!^t4OT1&s~9vjSTR4W;&(B1PFTfY z*9SHJ#})r$Q~zV<6o$1i_)8wQ%OUz1Nh#z2-;!Hi-a-m|TT(9yk$b|#K&c(k5dSM9 zz5wt|BYqJe1hV*oIC8%Dz~&F)pEu(30sk!G`Rh8skf^^yh|E9a>#WQOe1x<}Ga>^! z!oC0mLmo4R%mMt1Y3Bk!sOEOg32A3w0fP8ga!Ap1_EkG^~@_%TDHFJBABBQACg@ZSvIiE-ebY=vQemwIF?V1ljJ1Z;)u z&yBvZap1nD%QE7?!whX)95~(3PK*QhWGf6iMe32QfC;u|GctS*9C%@a_F-du22K=6( z1w{{&IpKIoxgKz)p=HE@rx@C}xZS)XqzpVEX3mls1k>GjUkVlx;Eje<2zZl_ysZOrzw{YxjgA!U@3R2n`+IZ^4|rZT z@yPwa)D0}D5I@AQ6aX$Yq#{5F^mZo5`Qig>-r*u+mXVbQxY&^9LeL6B$^+bFNOJ)% zHl)C9^AS=69igWbnk{nW-0u2e4dk57`w#}Kfu5D7=EbuQ&X`35CZrYI!I}vtl(Mn|10fEproqK^o0gR zQE0#gBbpB2fD3K22spUV3+pt{bag8(SY2KHnl7oXDyv>2?GoE4sEG?|65K{ejEd;w z;L#|=4a3BPQOEY2#G^TmgG@4UnP?|!%&39+@4Mgks_MS?l*!aN-QR!z_x;OV-hKOf z^mVWAYdJ+akXybfmih`Fp3>JE-&Zrmy}l|&vD8=ah_wcz{xyH}w^E$wA39t_aXM6H z6=SKrNThhRuWF@uudfOmlrf1{{3Kc^GP0~A6dBgctSlAX2X^l1{xRSEa*FgR+Xaer zsNFB$#8T0HV7ox~Y&Ypgiu5US3Pn29?wfu0Y&RiNT<5n}GsR*OfpsdF#EM`N@vtOT zgd`CUCb1%zMBHBYgGrnhOk!nN66b{^u`-y%dBG$Cho&4kd(qo^-lY6FbQMaD6j|6; z92OKS{I+kRI1(!Dj`A_k$)%sGHXVz?H;c9uS!0aPf{i|cxZCi^h9Y5P9 ziobwrumKMNR||fR)JAZs}zD)D7R`83tRmpV-)Gi;}!EW5}lD0 za=RZXYyHXw+bDO;L29GLsogzwn8z6hHJ|02mnY!H6x4Sm`^8 zQDh7=bFuW2?>32mUMW$wmcC!YvTh8o$?>Etf6q%3qwR{sx*ZI|0PVqfI zj|(Z5<`LXr1@mZT9&h=1oI{cM$RMD|WOQoHermV)sWnra;iq;E#hkBdp~wc6*_PrP zMHWTYO;{95s~OyuuEm{}ef~|D?G&$t>QLpXzYLr5=@C=LZKCdaEIZ6B>(PYZrOpt#LqU(opgM-JF>Fc932vPmI3e?iJ}diD_^D!(d} zvPdEGL68zS0%eHtUlqzGh14oYS>e|P0z=IBs!%p5q*g)7d3LC6c+`Ho|HyqS#piuh zjN&hSRV&38pwcT-@brEg;uV0>9u$A;t6~)2@l~x9_d;ddv-FWq4D6n@VG+aVtsmv9 zu*|zThK1{WUrpRhJ`9z%rTlL`?HoG`&m9)~Fn}qbW`t2m%_$D{TX7}DgUecxrL9Gx z?-v5y&+y&1P&~-Dic_RR-HI)nSSq>?Y>9&Im(%?a-~B}t=}^009^yW*iym~}O!xQu z6*`AvsrzQ%{r!F(=TKyYbRNM8H5hb7FzAJ0L05zXy)Z0j@avd!P@RNdttN`^_^KFd zIKi(|6U8216}t)|BZpiHprhHK>a%T>TYXPWcUYdnPRiYl^w=PJWuRP4J#gr-9cFx4 zy_`yNUI_xFdb~h6uK2Ct0BeVxSK|{$P^EQ%FH(QI!9kW^L@2Y zJk<9Uqgd)Icm)48e0&59-A39Z$<)p%NNKVupCH6gvDS`7^ zd@bRp{yMpW;`BgnI_;m&HX$C(T#18aa+0PXzAABW{_KqrE~?KtD%0`zY` zUa4_s1fNe}Hw`v+=L0VS@+s~$DD(c+Yfye2$fvaJ{OPw9Jln6$Cy#kBZZGT^_g0j@ z54;Ds3CKI)A3^zX;FCb!0KW_6mw>MVd4D(S_21Bc1pFAt8*2BXY}bc*v)v9f?+4*8 zDlTv6Wn4auJ`2}6<^azIHURDX80YKS=~?7sx6^^ftI2X8KUl)Ali2*{!FvhFZ;SA&AvS*^ZZW9?HUrNE@`E4zCWvi+D|kNyZUH_F z+y>wL|F&QBYx8&DIA9l$-)Q9rS#ADQ z?03!q@^h;EP^!(}0p7DfetNVY<@bU7rm1Z|6Z^ks0qcQ_fi`~$^lO0p+9p4R8^!Mg ze?5-pZU){CybEaCKLqptzJ3+${m`pKsnJQHY2#s4ni^#ZR1 z_5p7JZUo*9{4ucT$w;Fn89WL&5m*hh`R&j#y3%n6{3s9Y6GO7UD z`9;~?M|;bF`UkQ6Vc=uHO2iox5s!J;yqXC9ZnVQIz&C*v5###`=&uH@2i^qS0DK5& zRZo3U1I<)}BYlorYS!OtgJWXiNFEikOrf- z|L>YEp{6~O~0%=zV`^CU>BmB{B z2kf5#z6`Y6Z`tWalLA)GHRXvwQ!4)72j0;b|F>g2Zvz&YM&kOwe&zTcT4ys&`2(y! z2g+YE*Vtu&>#*Kz2b!hD|6Fh9BmX{Yz1_Cha8F%Qv?-NnUl04IEc;TfmeY+!lLg)k zycIYJaiZeA2;R%Uk>HPx$nQ4f#d(kO(j;qMN@4tP9=RZ5KG_9-p8#!tc75r03;gG- zc`u586Zr1e@Hub43qJF9Bl0J|AN)9YQGCwR%$xJ{A23gIUgmb=Hu&3!abwqy{uZHL zxkZNYU7*b$JI`oN0G{G& zE5e?<#o#Xmwgc_@Cl?w`0r)=rej4GQyi38~2i`#u{qX^KY)AIPuOj?^2>!>w&;F10 z+^%oIcKu=CHg4yw1~_Y(QKW#E1J^A#`Yphf&8B=Y@KT`VPQ3y9$D7LSx5JOkpA23W z=mLKNwE4T>XE*TIz_)FY2X9MeieDg*t%I5?5k_y`&U$gclcvVLj2H%8c^S`!S zAvbK!4(aR)HCVNT>g7)HQ2h{fN2q?NS}`P;MuohDe)nNv`h(TjQDORFsy|eJh^iVL z#y?b5qLE6MR;b}>_mQO=FtExiv#{_cGiVF3O z2>r1U`f(BZ<0ACON9e=P+*PQm0Dq8ZhNwU7w-<~Q#b7l;@#cWHK+qAjo;TgFh7-w0 zN)J~U1AXi~NL8wxH<>c_8I|6535%<@nc6>3-Wn^V{t5a@t0^vmzRl9Rq93Hjs>$dt zT~GbHM*aqcjFYXR*Ks#nexC67!SVJR(TC;#euVxL_-`98g8W`Epax4~I?q#(C#Q+S zMX&RznP7-x!9N=MCg=}`ehTz$&?lg0`&Zpz6gbvW^MoIkKlyzYzbS%$KH?7a82>{N zcNO$%jZxG=e>wC`(BA_6&Cu_G{sHKJ1pS6fjUo;GWAwk)D0I8)-@igX0R6#I)<3qV zy3CZv8c@FmzY6*c_#Z&O;c`Pf2^AY8^Skbsoqa~n`i_FWANoqOSbYonJCm@b zZHU|n;drRA#sm9hF6K%0W7K-IO#Ba0qtzK(kVpxH_4`WUD>WuCe`Y*CN2_7hymz^$ z56-LC!jC;ao1LlPJiitGD=q&|c>3V{{IcjrOZ(@r9r40R=5Ik?v))vco4pS`z0sBa z*AHulY%nz~KSEVqV!WITXLS+$wg|l|`l`}IAkUY9RHcI3oehjzXNaxf-v#}K z8;nAaZ~c2HBJNY*@0@RV6AY-=BKW_H(0>-8A1)JDSbOR_b9H}JooNEb5O=2NE2X}6 zzn=;I=5>a66!?wM_n{r$fc_#+k3tFPn|(%y?1$vxXWMm#97DUUkMMI>g#HQm;Yol7 zDeIqpOfak+UI)JkyBH=}6(d#*7~evbBuNBGHuzaeY*`~bkWMPF5t2gRGf=Seb-=O0A)*WYsr zYtN@eKT2xA{Yhyq@Ane?x7C~SO0={7WJZ{uPr+B1PaOCedQdq3mBF%eGPvKN;wsg}%x1zdOSJzl&bCgFO$t2R}T% z;LThgM)(;f2fJRoxh4^*zV{pD=}{60(RTbw=6h9V zKGE&OCC~0&F)1m*bd7$RDkM5n zX(yEx-)K&ebo@l#k?h=pwp`%2v7UC_h|4-V3yxdjjjgLyT8`z?DW(UNwyV!Ox>H1R zZa(EYww0!|O^xfb88?y2I2{b4gVuI*Ac%C#{N~yv^WyWCHpJsnD(jjK-PMI`yepCENINRt zaNg3|C5!6IX$4o>T2u>`w#Mfzgu8_e&7x{qQcuSV8kg18HpZ9DpC6mo5^t%kYn-RU zrKJY(WTD3!JxsAIy+S6JmmcYiC%ab9ox7lMQC)p}TJ`km88W^cr>L1$eVWSkxXG?W zzFaA-ST+VEs*}%WvT+$L-e4=I=bi5C8q05dQOlBeaea|$>9wUL(JqZ5?nAn{u~8>e zD0l5sV=28pnGRBy6ta1@oG3L*bd;-P5W87RmvFP4&#p0%1T>MoiYy;tlE1{ONZgSwMx=SJDKv}@wg0yy=c2cu*X)42fW3>(QrI8CJM?IX)%D-%llTRmd+MleRi!z;A4kB+D z#=B*#7vt(Nk@V(=a-EE7X$_sOj9hVLI?!v9PS;77WUf63p`|zHES1?zg01S#W{jn* zFS2NvOi{W@Zq_pEcDj?f-eTaXGgN%hGBK5@I^I(-Yov+HPLhQ=u?Y_Kk`+a-psG8h zQk|XYocB!77%U$SBmzLAhv#cBWgq}9_=CLy}A58M- zOR@LoeBGd4VWH&f*U&mo?#Q|)MZvZWjKnxRd)#(lm6B5$~QntRTp}@-9)>f40#W`D9J4C z_8FceziLBuT*##&o z#AR9DNhh=cq+Hrn)!xcbEn@YmtQ1{mt^C(JB0|b~GhVgRgN->vLVU{mr7&dExNLzi!9tcX9@&>}NHn z(uX;v_PoC5qt)O%P9lEavgdU`BJ*VuEEE6Pvgh$U@y7*P8f08*@3ZWAU6IJ+YVz&+ zKLmUBAI}#NhmD}6!K(72dQ{4~iD=L3l*CiG0Csl#=PY|(&m>-NUH@gf!JT?h1f8N@ zhxCu<)ptH($~K>6;%|heujSF6*GG3Bp#3{ytH&Pgc^$PM_G}oAPsU|G-XXTS{e1hM zR!K?8byp8mjWzygPt@0SO6~pgmD`Lx0XzFyt*ZGzHXh)qsuW#%0vJ>^dl;6td4f4OuJto3_ecmwdvBtk` zKPkd~{MCke@(GM=(6*lrd%OLXJYbmjS|`tFPdp3uv{jYHZoGiLw!v}Bai!-cjy=OP|A)PA?7vL|EVSc~im+e* NXJdb^WndN6{{s3sT5bRU literal 0 HcmV?d00001 diff --git a/libs/shapelib/shptreedump_autogen/mocs_compilation.cpp b/libs/shapelib/shptreedump_autogen/mocs_compilation.cpp new file mode 100644 index 000000000..bda67f76e --- /dev/null +++ b/libs/shapelib/shptreedump_autogen/mocs_compilation.cpp @@ -0,0 +1,3 @@ +// This file is autogenerated. Changes will be overwritten. +// No files found that require moc or the moc files are included +enum some_compilers { need_more_than_nothing }; diff --git a/libs/snake/.gitignore b/libs/snake/.gitignore new file mode 100644 index 000000000..fab7372d7 --- /dev/null +++ b/libs/snake/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/libs/snake/CMakeLists.txt b/libs/snake/CMakeLists.txt deleted file mode 100644 index 2b46b828d..000000000 --- a/libs/snake/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -add_library(snake - STATIC - snake.cpp - snake_geometry.cpp -) -find_package(GeographicLib REQUIRED) -find_package(ortools CONFIG REQUIRED) - - -target_link_libraries (snake ${GeographicLib_LIBRARIES} polyclipping ${ORTOOLS_LIBRARIES}) - -target_include_directories(snake PRIVATE polylabel) # polylabel -target_include_directories(snake PUBLIC include) # polylabel - -add_subdirectory(test) - - - diff --git a/libs/snake/Makefile b/libs/snake/Makefile deleted file mode 100644 index 600fb5d09..000000000 --- a/libs/snake/Makefile +++ /dev/null @@ -1,326 +0,0 @@ -# CMAKE generated file: DO NOT EDIT! -# Generated by "Unix Makefiles" Generator, CMake Version 3.18 - -# Default target executed when no arguments are given to make. -default_target: all - -.PHONY : default_target - -# Allow only one "make -f Makefile2" at a time, but pass parallelism. -.NOTPARALLEL: - - -#============================================================================= -# Special targets provided by cmake. - -# Disable implicit rules so canonical targets will work. -.SUFFIXES: - - -# Disable VCS-based implicit rules. -% : %,v - - -# Disable VCS-based implicit rules. -% : RCS/% - - -# Disable VCS-based implicit rules. -% : RCS/%,v - - -# Disable VCS-based implicit rules. -% : SCCS/s.% - - -# Disable VCS-based implicit rules. -% : s.% - - -.SUFFIXES: .hpux_make_needs_suffix_list - - -# Command-line flag to silence nested $(MAKE). -$(VERBOSE)MAKESILENT = -s - -# Suppress display of executed commands. -$$(VERBOSE).SILENT: - - -# A target that is always out of date. -cmake_force: - -.PHONY : cmake_force - -#============================================================================= -# Set environment variables for the build. - -# The shell in which to execute make rules. -SHELL = /bin/sh - -# The CMake executable. -CMAKE_COMMAND = /usr/local/bin/cmake - -# The command to remove a file. -RM = /usr/local/bin/cmake -E rm -f - -# Escaping for special characters. -EQUALS = = - -# The top-level source directory on which CMake was run. -CMAKE_SOURCE_DIR = /home/valentin/Desktop/drones/qgroundcontrol - -# The top-level build directory on which CMake was run. -CMAKE_BINARY_DIR = /home/valentin/Desktop/drones/qgroundcontrol - -#============================================================================= -# Targets provided globally by CMake. - -# Special rule for the target install/strip -install/strip: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip - -# Special rule for the target install/strip -install/strip/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." - /usr/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake -.PHONY : install/strip/fast - -# Special rule for the target edit_cache -edit_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." - /usr/local/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. -.PHONY : edit_cache - -# Special rule for the target edit_cache -edit_cache/fast: edit_cache - -.PHONY : edit_cache/fast - -# Special rule for the target rebuild_cache -rebuild_cache: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." - /usr/local/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) -.PHONY : rebuild_cache - -# Special rule for the target rebuild_cache -rebuild_cache/fast: rebuild_cache - -.PHONY : rebuild_cache/fast - -# Special rule for the target list_install_components -list_install_components: - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" -.PHONY : list_install_components - -# Special rule for the target list_install_components -list_install_components/fast: list_install_components - -.PHONY : list_install_components/fast - -# Special rule for the target install/local -install/local: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local - -# Special rule for the target install/local -install/local/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." - /usr/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake -.PHONY : install/local/fast - -# Special rule for the target install -install: preinstall - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /usr/local/bin/cmake -P cmake_install.cmake -.PHONY : install - -# Special rule for the target install -install/fast: preinstall/fast - @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." - /usr/local/bin/cmake -P cmake_install.cmake -.PHONY : install/fast - -# The main all target -all: cmake_check_build_system - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -E cmake_progress_start /home/valentin/Desktop/drones/qgroundcontrol/CMakeFiles /home/valentin/Desktop/drones/qgroundcontrol/libs/snake//CMakeFiles/progress.marks - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/all - $(CMAKE_COMMAND) -E cmake_progress_start /home/valentin/Desktop/drones/qgroundcontrol/CMakeFiles 0 -.PHONY : all - -# The main clean target -clean: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/clean -.PHONY : clean - -# The main clean target -clean/fast: clean - -.PHONY : clean/fast - -# Prepare targets for installation. -preinstall: all - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/preinstall -.PHONY : preinstall - -# Prepare targets for installation. -preinstall/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/preinstall -.PHONY : preinstall/fast - -# clear depends -depend: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 -.PHONY : depend - -# Convenience name for target. -libs/snake/CMakeFiles/snake.dir/rule: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/CMakeFiles/snake.dir/rule -.PHONY : libs/snake/CMakeFiles/snake.dir/rule - -# Convenience name for target. -snake: libs/snake/CMakeFiles/snake.dir/rule - -.PHONY : snake - -# fast build rule for target. -snake/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/build -.PHONY : snake/fast - -# Convenience name for target. -libs/snake/CMakeFiles/snake_autogen.dir/rule: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 libs/snake/CMakeFiles/snake_autogen.dir/rule -.PHONY : libs/snake/CMakeFiles/snake_autogen.dir/rule - -# Convenience name for target. -snake_autogen: libs/snake/CMakeFiles/snake_autogen.dir/rule - -.PHONY : snake_autogen - -# fast build rule for target. -snake_autogen/fast: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake_autogen.dir/build.make libs/snake/CMakeFiles/snake_autogen.dir/build -.PHONY : snake_autogen/fast - -snake.o: snake.cpp.o - -.PHONY : snake.o - -# target to build an object file -snake.cpp.o: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake.cpp.o -.PHONY : snake.cpp.o - -snake.i: snake.cpp.i - -.PHONY : snake.i - -# target to preprocess a source file -snake.cpp.i: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake.cpp.i -.PHONY : snake.cpp.i - -snake.s: snake.cpp.s - -.PHONY : snake.s - -# target to generate assembly for a file -snake.cpp.s: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake.cpp.s -.PHONY : snake.cpp.s - -snake_autogen/mocs_compilation.o: snake_autogen/mocs_compilation.cpp.o - -.PHONY : snake_autogen/mocs_compilation.o - -# target to build an object file -snake_autogen/mocs_compilation.cpp.o: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_autogen/mocs_compilation.cpp.o -.PHONY : snake_autogen/mocs_compilation.cpp.o - -snake_autogen/mocs_compilation.i: snake_autogen/mocs_compilation.cpp.i - -.PHONY : snake_autogen/mocs_compilation.i - -# target to preprocess a source file -snake_autogen/mocs_compilation.cpp.i: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_autogen/mocs_compilation.cpp.i -.PHONY : snake_autogen/mocs_compilation.cpp.i - -snake_autogen/mocs_compilation.s: snake_autogen/mocs_compilation.cpp.s - -.PHONY : snake_autogen/mocs_compilation.s - -# target to generate assembly for a file -snake_autogen/mocs_compilation.cpp.s: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_autogen/mocs_compilation.cpp.s -.PHONY : snake_autogen/mocs_compilation.cpp.s - -snake_geometry.o: snake_geometry.cpp.o - -.PHONY : snake_geometry.o - -# target to build an object file -snake_geometry.cpp.o: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_geometry.cpp.o -.PHONY : snake_geometry.cpp.o - -snake_geometry.i: snake_geometry.cpp.i - -.PHONY : snake_geometry.i - -# target to preprocess a source file -snake_geometry.cpp.i: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_geometry.cpp.i -.PHONY : snake_geometry.cpp.i - -snake_geometry.s: snake_geometry.cpp.s - -.PHONY : snake_geometry.s - -# target to generate assembly for a file -snake_geometry.cpp.s: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(MAKE) $(MAKESILENT) -f libs/snake/CMakeFiles/snake.dir/build.make libs/snake/CMakeFiles/snake.dir/snake_geometry.cpp.s -.PHONY : snake_geometry.cpp.s - -# Help Target -help: - @echo "The following are some of the valid targets for this Makefile:" - @echo "... all (the default if no target is provided)" - @echo "... clean" - @echo "... depend" - @echo "... edit_cache" - @echo "... install" - @echo "... install/local" - @echo "... install/strip" - @echo "... list_install_components" - @echo "... rebuild_cache" - @echo "... snake_autogen" - @echo "... snake" - @echo "... snake.o" - @echo "... snake.i" - @echo "... snake.s" - @echo "... snake_autogen/mocs_compilation.o" - @echo "... snake_autogen/mocs_compilation.i" - @echo "... snake_autogen/mocs_compilation.s" - @echo "... snake_geometry.o" - @echo "... snake_geometry.i" - @echo "... snake_geometry.s" -.PHONY : help - - - -#============================================================================= -# Special targets to cleanup operation of make. - -# Special rule to run CMake to check the build system integrity. -# No rule that depends on this can have commands that come from listfiles -# because they might be regenerated. -cmake_check_build_system: - cd /home/valentin/Desktop/drones/qgroundcontrol && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 -.PHONY : cmake_check_build_system - diff --git a/libs/snake/cmake_install.cmake b/libs/snake/cmake_install.cmake deleted file mode 100644 index 8b04e83a3..000000000 --- a/libs/snake/cmake_install.cmake +++ /dev/null @@ -1,50 +0,0 @@ -# Install script for directory: /home/valentin/Desktop/drones/qgroundcontrol/libs/snake - -# Set the install prefix -if(NOT DEFINED CMAKE_INSTALL_PREFIX) - set(CMAKE_INSTALL_PREFIX "/usr/local") -endif() -string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") - -# Set the install configuration name. -if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) - if(BUILD_TYPE) - string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" - CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") - else() - set(CMAKE_INSTALL_CONFIG_NAME "RelWithDebInfo") - endif() - message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") -endif() - -# Set the component getting installed. -if(NOT CMAKE_INSTALL_COMPONENT) - if(COMPONENT) - message(STATUS "Install component: \"${COMPONENT}\"") - set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") - else() - set(CMAKE_INSTALL_COMPONENT) - endif() -endif() - -# Install shared libraries without execute permission? -if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) - set(CMAKE_INSTALL_SO_NO_EXE "1") -endif() - -# Is this installation the result of a crosscompile? -if(NOT DEFINED CMAKE_CROSSCOMPILING) - set(CMAKE_CROSSCOMPILING "FALSE") -endif() - -# Set default install directory permissions. -if(NOT DEFINED CMAKE_OBJDUMP) - set(CMAKE_OBJDUMP "/usr/bin/objdump") -endif() - -if(NOT CMAKE_INSTALL_LOCAL_ONLY) - # Include the install script for each subdirectory. - include("/home/valentin/Desktop/drones/qgroundcontrol/libs/snake/test/cmake_install.cmake") - -endif() - diff --git a/libs/snake/polylabel/mapbox/feature.hpp b/libs/snake/mapbox/feature.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/feature.hpp rename to libs/snake/mapbox/feature.hpp diff --git a/libs/snake/polylabel/mapbox/geometry.hpp b/libs/snake/mapbox/geometry.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry.hpp rename to libs/snake/mapbox/geometry.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/box.hpp b/libs/snake/mapbox/geometry/box.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/box.hpp rename to libs/snake/mapbox/geometry/box.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/empty.hpp b/libs/snake/mapbox/geometry/empty.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/empty.hpp rename to libs/snake/mapbox/geometry/empty.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/envelope.hpp b/libs/snake/mapbox/geometry/envelope.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/envelope.hpp rename to libs/snake/mapbox/geometry/envelope.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/for_each_point.hpp b/libs/snake/mapbox/geometry/for_each_point.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/for_each_point.hpp rename to libs/snake/mapbox/geometry/for_each_point.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/geometry.hpp b/libs/snake/mapbox/geometry/geometry.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/geometry.hpp rename to libs/snake/mapbox/geometry/geometry.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/line_string.hpp b/libs/snake/mapbox/geometry/line_string.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/line_string.hpp rename to libs/snake/mapbox/geometry/line_string.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/multi_line_string.hpp b/libs/snake/mapbox/geometry/multi_line_string.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/multi_line_string.hpp rename to libs/snake/mapbox/geometry/multi_line_string.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/multi_point.hpp b/libs/snake/mapbox/geometry/multi_point.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/multi_point.hpp rename to libs/snake/mapbox/geometry/multi_point.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/multi_polygon.hpp b/libs/snake/mapbox/geometry/multi_polygon.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/multi_polygon.hpp rename to libs/snake/mapbox/geometry/multi_polygon.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/point.hpp b/libs/snake/mapbox/geometry/point.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/point.hpp rename to libs/snake/mapbox/geometry/point.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/point_arithmetic.hpp b/libs/snake/mapbox/geometry/point_arithmetic.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/point_arithmetic.hpp rename to libs/snake/mapbox/geometry/point_arithmetic.hpp diff --git a/libs/snake/polylabel/mapbox/geometry/polygon.hpp b/libs/snake/mapbox/geometry/polygon.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry/polygon.hpp rename to libs/snake/mapbox/geometry/polygon.hpp diff --git a/libs/snake/polylabel/mapbox/geometry_io.hpp b/libs/snake/mapbox/geometry_io.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/geometry_io.hpp rename to libs/snake/mapbox/geometry_io.hpp diff --git a/libs/snake/polylabel/mapbox/optional.hpp b/libs/snake/mapbox/optional.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/optional.hpp rename to libs/snake/mapbox/optional.hpp diff --git a/libs/snake/polylabel/mapbox/polylabel/polylabel.hpp b/libs/snake/mapbox/polylabel.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/polylabel/polylabel.hpp rename to libs/snake/mapbox/polylabel.hpp diff --git a/libs/snake/polylabel/mapbox/recursive_wrapper.hpp b/libs/snake/mapbox/recursive_wrapper.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/recursive_wrapper.hpp rename to libs/snake/mapbox/recursive_wrapper.hpp diff --git a/libs/snake/polylabel/mapbox/variant.hpp b/libs/snake/mapbox/variant.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/variant.hpp rename to libs/snake/mapbox/variant.hpp diff --git a/libs/snake/polylabel/mapbox/variant_io.hpp b/libs/snake/mapbox/variant_io.hpp similarity index 100% rename from libs/snake/polylabel/mapbox/variant_io.hpp rename to libs/snake/mapbox/variant_io.hpp diff --git a/libs/snake/snake.cpp b/libs/snake/snake.cpp index cdab73cbe..9df954b7b 100644 --- a/libs/snake/snake.cpp +++ b/libs/snake/snake.cpp @@ -1,7 +1,7 @@ #include #include "snake.h" -#include +#include "clipper.hpp" #define CLIPPER_SCALE 10000 using namespace snake_geometry; diff --git a/libs/snake/include/snake.h b/libs/snake/snake.h similarity index 100% rename from libs/snake/include/snake.h rename to libs/snake/snake.h diff --git a/libs/snake/snake.pro b/libs/snake/snake.pro new file mode 100644 index 000000000..5c2d97846 --- /dev/null +++ b/libs/snake/snake.pro @@ -0,0 +1,62 @@ +CONFIG -= qt + +TEMPLATE = lib +DEFINES += SNAKE_LIBRARY + +CONFIG += c++14 + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + snake.cpp \ + snake_geometry.cpp \ + test/test_snake.cpp \ + test/test_snake_geometry.cpp + +HEADERS += \ + catch.hpp \ + polylabel/mapbox/feature.hpp \ + polylabel/mapbox/geometry.hpp \ + polylabel/mapbox/geometry/box.hpp \ + polylabel/mapbox/geometry/empty.hpp \ + polylabel/mapbox/geometry/envelope.hpp \ + polylabel/mapbox/geometry/for_each_point.hpp \ + polylabel/mapbox/geometry/geometry.hpp \ + polylabel/mapbox/geometry/line_string.hpp \ + polylabel/mapbox/geometry/multi_line_string.hpp \ + polylabel/mapbox/geometry/multi_point.hpp \ + polylabel/mapbox/geometry/multi_polygon.hpp \ + polylabel/mapbox/geometry/point.hpp \ + polylabel/mapbox/geometry/point_arithmetic.hpp \ + polylabel/mapbox/geometry/polygon.hpp \ + polylabel/mapbox/geometry_io.hpp \ + polylabel/mapbox/optional.hpp \ + polylabel/mapbox/polylabel/polylabel.hpp \ + polylabel/mapbox/recursive_wrapper.hpp \ + polylabel/mapbox/variant.hpp \ + polylabel/mapbox/variant_io.hpp \ + snake_geometry.h \ + snake_global.h \ + snake.h + +# Default rules for deployment. +unix { + target.path = /usr/lib +} +!isEmpty(target.path): INSTALLS += target + +win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/./release/ -lsnake +else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/./debug/ -lsnake +else:unix: LIBS += -L$$OUT_PWD/./ -lsnake + +INCLUDEPATH += $$PWD/../clipper/clipper +DEPENDPATH += $$PWD/../clipper/clipper diff --git a/libs/snake/snake_geometry.cpp b/libs/snake/snake_geometry.cpp index a6ab3916c..e26a5f1ac 100644 --- a/libs/snake/snake_geometry.cpp +++ b/libs/snake/snake_geometry.cpp @@ -308,10 +308,7 @@ bool dijkstraAlgorithm(const size_t numElements, std::vector &elementPath, std::function distanceDij) { - if ( numElements < 0 - || startIndex < 0 - || endIndex < 0 - || startIndex >= numElements + if ( startIndex >= numElements || endIndex >= numElements || endIndex == startIndex) { return false; diff --git a/libs/snake/include/snake_geometry.h b/libs/snake/snake_geometry.h similarity index 100% rename from libs/snake/include/snake_geometry.h rename to libs/snake/snake_geometry.h diff --git a/libs/snake/snake_geometry.h.orig b/libs/snake/snake_geometry.h.orig deleted file mode 100644 index 1dff39fa2..000000000 --- a/libs/snake/snake_geometry.h.orig +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include -#include - -#include "WGS84toCartesian.hpp" - -namespace snake_geometry { - -typedef std::array Point2D; -typedef std::vector Point2DList; -typedef std::array Point3D; -typedef std::vector Point3DList; -typedef std::array GeoPoint2D; -typedef std::vector GeoPoint2DList; -typedef std::array GeoPoint3D; -typedef std::vector GeoPoint3DList; - -typedef struct { - double width; - double height; - double angle; - std::array corners; -}min_bbox_rt; - -<<<<<<< HEAD - Point3D toENU(const GeoPoint3D &WGS84Reference, const GeoPoint3D &WGS84Position); - GeoPoint3D fromENU(const Point3D &WGS84Reference, const Point3D &CartesianPosition); -======= -Point3D toENU(const Point3D &WGS84Reference, const Point3D &WGS84Position); -Point3D fromENU(const Point3D &WGS84Reference, const Point3D &CartesianPosition); ->>>>>>> 5687fb4553282f37531aa25fac4d66ec9a84932e - -Point2D polygonCenter(const Point2DList &polygon); -min_bbox_rt minimalBoundingBox(const Point2DList &polygon); - -} diff --git a/libs/snake/snake_global.h b/libs/snake/snake_global.h new file mode 100644 index 000000000..2cfda3daa --- /dev/null +++ b/libs/snake/snake_global.h @@ -0,0 +1,18 @@ +#ifndef SNAKE_GLOBAL_H +#define SNAKE_GLOBAL_H + +#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# define Q_DECL_EXPORT __declspec(dllexport) +# define Q_DECL_IMPORT __declspec(dllimport) +#else +# define Q_DECL_EXPORT __attribute__((visibility("default"))) +# define Q_DECL_IMPORT __attribute__((visibility("default"))) +#endif + +#if defined(SNAKE_LIBRARY) +# define SNAKE_EXPORT Q_DECL_EXPORT +#else +# define SNAKE_EXPORT Q_DECL_IMPORT +#endif + +#endif // SNAKE_GLOBAL_H diff --git a/libs/snake_old/catch.hpp b/libs/snake_old/catch.hpp new file mode 100644 index 000000000..2c1b9cdbc --- /dev/null +++ b/libs/snake_old/catch.hpp @@ -0,0 +1,17707 @@ +/* + * Catch v2.12.2 + * Generated: 2020-05-25 15:09:23.791719 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#pragma once +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 12 +#define CATCH_VERSION_PATCH 2 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(__cpp_lib_uncaught_exceptions) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template