Commit 2601b482 authored by Valentin Platzgummer's avatar Valentin Platzgummer

SnakeWorker added

parent 5ac59ffd
......@@ -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
}
cmake_minimum_required(VERSION 3.14)
project(polyclipping)
add_library(polyclipping
STATIC
clipper.cpp)
target_include_directories(polyclipping PUBLIC include)
# 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
# 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
This source diff could not be displayed because it is too large. You can view the blob instead.
/*******************************************************************************
* *
* 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 <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
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<LocalMinimum> 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<cInt> 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<cInt> 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<DoublePoint> 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 <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
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<LocalMinimum> 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<cInt> 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<cInt> 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<DoublePoint> 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
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
#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
# 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()
// 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"
// 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 };
// 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 };
// 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 };
// 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 };
// 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 };
// 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 };
// 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 };
// 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 };
// 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 };
# 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
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)
# 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
# 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()
#include <iostream>
#include "snake.h"
#include <clipper.hpp>
#include "clipper.hpp"
#define CLIPPER_SCALE 10000
using namespace snake_geometry;
......
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
......@@ -308,10 +308,7 @@ bool dijkstraAlgorithm(const size_t numElements,
std::vector<size_t> &elementPath,
std::function<double (const size_t, const size_t)> distanceDij)
{
if ( numElements < 0
|| startIndex < 0
|| endIndex < 0
|| startIndex >= numElements
if ( startIndex >= numElements
|| endIndex >= numElements
|| endIndex == startIndex) {
return false;
......
#pragma once
#include <vector>
#include <array>
#include "WGS84toCartesian.hpp"
namespace snake_geometry {
typedef std::array<double, 2> Point2D;
typedef std::vector<Point2D> Point2DList;
typedef std::array<double, 3> Point3D;
typedef std::vector<Point3D> Point3DList;
typedef std::array<double, 2> GeoPoint2D;
typedef std::vector<GeoPoint2D> GeoPoint2DList;
typedef std::array<double, 3> GeoPoint3D;
typedef std::vector<GeoPoint3D> GeoPoint3DList;
typedef struct {
double width;
double height;
double angle;
std::array<Point2D,4> 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);
}
#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
This source diff could not be displayed because it is too large. You can view the blob instead.
#pragma once
#include <mapbox/geometry.hpp>
#include <mapbox/variant.hpp>
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
namespace mapbox {
namespace feature {
struct value;
struct null_value_t
{
};
constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
constexpr bool operator<(const null_value_t&, const null_value_t&) { return false; }
constexpr null_value_t null_value = null_value_t();
// Multiple numeric types (uint64_t, int64_t, double) are present in order to support
// the widest possible range of JSON numbers, which do not have a maximum range.
// Implementations that produce `value`s should use that order for type preference,
// using uint64_t for positive integers, int64_t for negative integers, and double
// for non-integers and integers outside the range of 64 bits.
using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
mapbox::util::recursive_wrapper<std::vector<value>>,
mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
struct value : value_base
{
using value_base::value_base;
};
using property_map = std::unordered_map<std::string, value>;
// The same considerations and requirement for numeric types apply as for `value_base`.
using identifier = mapbox::util::variant<null_value_t, uint64_t, int64_t, double, std::string>;
template <class T>
struct feature
{
using coordinate_type = T;
using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
geometry_type geometry;
property_map properties;
identifier id;
feature()
: geometry(),
properties(),
id() {}
feature(geometry_type const& geom_)
: geometry(geom_),
properties(),
id() {}
feature(geometry_type&& geom_)
: geometry(std::move(geom_)),
properties(),
id() {}
feature(geometry_type const& geom_, property_map const& prop_)
: geometry(geom_), properties(prop_), id() {}
feature(geometry_type&& geom_, property_map&& prop_)
: geometry(std::move(geom_)),
properties(std::move(prop_)),
id() {}
feature(geometry_type const& geom_, property_map const& prop_, identifier const& id_)
: geometry(geom_),
properties(prop_),
id(id_) {}
feature(geometry_type&& geom_, property_map&& prop_, identifier&& id_)
: geometry(std::move(geom_)),
properties(std::move(prop_)),
id(std::move(id_)) {}
};
template <class T>
constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
{
return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
}
template <class T>
constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
{
return !(lhs == rhs);
}
template <class T, template <typename...> class Cont = std::vector>
struct feature_collection : Cont<feature<T>>
{
using coordinate_type = T;
using feature_type = feature<T>;
using container_type = Cont<feature_type>;
using size_type = typename container_type::size_type;
template <class... Args>
feature_collection(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
feature_collection(std::initializer_list<feature_type> args)
: container_type(std::move(args)) {}
};
} // namespace feature
} // namespace mapbox
#pragma once
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/line_string.hpp>
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/multi_point.hpp>
#include <mapbox/geometry/multi_line_string.hpp>
#include <mapbox/geometry/multi_polygon.hpp>
#include <mapbox/geometry/geometry.hpp>
#include <mapbox/geometry/point_arithmetic.hpp>
#include <mapbox/geometry/for_each_point.hpp>
#include <mapbox/geometry/envelope.hpp>
#pragma once
#include <mapbox/geometry/point.hpp>
namespace mapbox {
namespace geometry {
template <typename T>
struct box
{
using coordinate_type = T;
using point_type = point<coordinate_type>;
constexpr box(point_type const& min_, point_type const& max_)
: min(min_), max(max_)
{
}
point_type min;
point_type max;
};
template <typename T>
constexpr bool operator==(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min == rhs.min && lhs.max == rhs.max;
}
template <typename T>
constexpr bool operator!=(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min != rhs.min || lhs.max != rhs.max;
}
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
struct empty
{
}; // this Geometry type represents the empty point set, ∅, for the coordinate space (OGC Simple Features).
constexpr bool operator==(empty, empty) { return true; }
constexpr bool operator!=(empty, empty) { return false; }
constexpr bool operator<(empty, empty) { return false; }
constexpr bool operator>(empty, empty) { return false; }
constexpr bool operator<=(empty, empty) { return true; }
constexpr bool operator>=(empty, empty) { return true; }
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/box.hpp>
#include <mapbox/geometry/for_each_point.hpp>
#include <limits>
namespace mapbox {
namespace geometry {
template <typename G, typename T = typename G::coordinate_type>
box<T> envelope(G const& geometry)
{
using limits = std::numeric_limits<T>;
T min_t = limits::has_infinity ? -limits::infinity() : limits::min();
T max_t = limits::has_infinity ? limits::infinity() : limits::max();
point<T> min(max_t, max_t);
point<T> max(min_t, min_t);
for_each_point(geometry, [&](point<T> const& point) {
if (min.x > point.x) min.x = point.x;
if (min.y > point.y) min.y = point.y;
if (max.x < point.x) max.x = point.x;
if (max.y < point.y) max.y = point.y;
});
return box<T>(min, max);
}
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/geometry.hpp>
namespace mapbox {
namespace geometry {
template <typename F>
void for_each_point(mapbox::geometry::empty const&, F&&)
{
}
template <typename Point, typename F>
auto for_each_point(Point&& point, F&& f)
-> decltype(point.x, point.y, void())
{
f(std::forward<Point>(point));
}
template <typename Container, typename F>
auto for_each_point(Container&& container, F&& f)
-> decltype(container.begin(), container.end(), void());
template <typename... Types, typename F>
void for_each_point(mapbox::util::variant<Types...> const& geom, F&& f)
{
mapbox::util::variant<Types...>::visit(geom, [&](auto const& g) {
for_each_point(g, f);
});
}
template <typename... Types, typename F>
void for_each_point(mapbox::util::variant<Types...>& geom, F&& f)
{
mapbox::util::variant<Types...>::visit(geom, [&](auto& g) {
for_each_point(g, f);
});
}
template <typename Container, typename F>
auto for_each_point(Container&& container, F&& f)
-> decltype(container.begin(), container.end(), void())
{
for (auto& e : container)
{
for_each_point(e, f);
}
}
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/empty.hpp>
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/line_string.hpp>
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/multi_point.hpp>
#include <mapbox/geometry/multi_line_string.hpp>
#include <mapbox/geometry/multi_polygon.hpp>
#include <mapbox/variant.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct geometry_collection;
template <typename T, template <typename...> class Cont = std::vector>
using geometry_base = mapbox::util::variant<empty,
point<T>,
line_string<T, Cont>,
polygon<T, Cont>,
multi_point<T, Cont>,
multi_line_string<T, Cont>,
multi_polygon<T, Cont>,
geometry_collection<T, Cont>>;
template <typename T, template <typename...> class Cont = std::vector>
struct geometry : geometry_base<T, Cont>
{
using coordinate_type = T;
using geometry_base<T>::geometry_base;
};
template <typename T, template <typename...> class Cont>
struct geometry_collection : Cont<geometry<T>>
{
using coordinate_type = T;
using geometry_type = geometry<T>;
using container_type = Cont<geometry_type>;
using size_type = typename container_type::size_type;
template <class... Args>
geometry_collection(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
geometry_collection(std::initializer_list<geometry_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct line_string : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
line_string(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
line_string(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/line_string.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_line_string : Cont<line_string<T>>
{
using coordinate_type = T;
using line_string_type = line_string<T>;
using container_type = Cont<line_string_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_line_string(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_line_string(std::initializer_list<line_string_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_point : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_point(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_point(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/polygon.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_polygon : Cont<polygon<T>>
{
using coordinate_type = T;
using polygon_type = polygon<T>;
using container_type = Cont<polygon_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_polygon(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_polygon(std::initializer_list<polygon_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
template <typename T>
struct point
{
using coordinate_type = T;
constexpr point()
: x(), y()
{
}
constexpr point(T x_, T y_)
: x(x_), y(y_)
{
}
T x;
T y;
};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
template <typename T>
constexpr bool operator==(point<T> const& lhs, point<T> const& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
#pragma GCC diagnostic pop
template <typename T>
constexpr bool operator!=(point<T> const& lhs, point<T> const& rhs)
{
return !(lhs == rhs);
}
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
template <typename T>
point<T> operator+(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x + rhs.x, lhs.y + rhs.y);
}
template <typename T>
point<T> operator+(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x + rhs, lhs.y + rhs);
}
template <typename T>
point<T> operator-(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x - rhs.x, lhs.y - rhs.y);
}
template <typename T>
point<T> operator-(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x - rhs, lhs.y - rhs);
}
template <typename T>
point<T> operator*(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x * rhs.x, lhs.y * rhs.y);
}
template <typename T>
point<T> operator*(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x * rhs, lhs.y * rhs);
}
template <typename T>
point<T> operator/(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x / rhs.x, lhs.y / rhs.y);
}
template <typename T>
point<T> operator/(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x / rhs, lhs.y / rhs);
}
template <typename T>
point<T>& operator+=(point<T>& lhs, point<T> const& rhs)
{
lhs.x += rhs.x;
lhs.y += rhs.y;
return lhs;
}
template <typename T>
point<T>& operator+=(point<T>& lhs, T const& rhs)
{
lhs.x += rhs;
lhs.y += rhs;
return lhs;
}
template <typename T>
point<T>& operator-=(point<T>& lhs, point<T> const& rhs)
{
lhs.x -= rhs.x;
lhs.y -= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator-=(point<T>& lhs, T const& rhs)
{
lhs.x -= rhs;
lhs.y -= rhs;
return lhs;
}
template <typename T>
point<T>& operator*=(point<T>& lhs, point<T> const& rhs)
{
lhs.x *= rhs.x;
lhs.y *= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator*=(point<T>& lhs, T const& rhs)
{
lhs.x *= rhs;
lhs.y *= rhs;
return lhs;
}
template <typename T>
point<T>& operator/=(point<T>& lhs, point<T> const& rhs)
{
lhs.x /= rhs.x;
lhs.y /= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator/=(point<T>& lhs, T const& rhs)
{
lhs.x /= rhs;
lhs.y /= rhs;
return lhs;
}
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct linear_ring : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
linear_ring(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
linear_ring(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
template <typename T, template <typename...> class Cont = std::vector>
struct polygon : Cont<linear_ring<T>>
{
using coordinate_type = T;
using linear_ring_type = linear_ring<T>;
using container_type = Cont<linear_ring_type>;
using size_type = typename container_type::size_type;
template <class... Args>
polygon(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
polygon(std::initializer_list<linear_ring_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/empty.hpp>
#include <mapbox/feature.hpp>
#include <iostream>
#include <string>
namespace mapbox {
namespace geometry {
std::ostream& operator<<(std::ostream& os, const empty&)
{
return os << "[]";
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const point<T>& point)
{
return os << "[" << point.x << "," << point.y << "]";
}
template <typename T, template <class, class...> class C, class... Args>
std::ostream& operator<<(std::ostream& os, const C<T, Args...>& cont)
{
os << "[";
for (auto it = cont.cbegin();;)
{
os << *it;
if (++it == cont.cend())
{
break;
}
os << ",";
}
return os << "]";
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const line_string<T>& geom)
{
return os << static_cast<typename line_string<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const linear_ring<T>& geom)
{
return os << static_cast<typename linear_ring<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const polygon<T>& geom)
{
return os << static_cast<typename polygon<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_point<T>& geom)
{
return os << static_cast<typename multi_point<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_line_string<T>& geom)
{
return os << static_cast<typename multi_line_string<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_polygon<T>& geom)
{
return os << static_cast<typename multi_polygon<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const geometry<T>& geom)
{
geometry<T>::visit(geom, [&](const auto& g) { os << g; });
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const geometry_collection<T>& geom)
{
return os << static_cast<typename geometry_collection<T>::container_type>(geom);
}
} // namespace geometry
namespace feature {
std::ostream& operator<<(std::ostream& os, const null_value_t&)
{
return os << "[]";
}
} // namespace feature
} // namespace mapbox
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
#define MAPBOX_UTIL_OPTIONAL_HPP
#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
#include <type_traits>
#include <utility>
#include "variant.hpp"
namespace mapbox {
namespace util {
template <typename T>
class optional
{
static_assert(!std::is_reference<T>::value, "optional doesn't support references");
struct none_type
{
};
variant<none_type, T> variant_;
public:
optional() = default;
optional(optional const& rhs)
{
if (this != &rhs)
{ // protect against invalid self-assignment
variant_ = rhs.variant_;
}
}
optional(T const& v) { variant_ = v; }
explicit operator bool() const noexcept { return variant_.template is<T>(); }
T const& get() const { return variant_.template get<T>(); }
T& get() { return variant_.template get<T>(); }
T const& operator*() const { return this->get(); }
T operator*() { return this->get(); }
optional& operator=(T const& v)
{
variant_ = v;
return *this;
}
optional& operator=(optional const& rhs)
{
if (this != &rhs)
{
variant_ = rhs.variant_;
}
return *this;
}
template <typename... Args>
void emplace(Args&&... args)
{
variant_ = T{std::forward<Args>(args)...};
}
void reset() { variant_ = none_type{}; }
}; // class optional
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_OPTIONAL_HPP
#pragma once
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/envelope.hpp>
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/point_arithmetic.hpp>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
namespace mapbox {
namespace detail {
// get squared distance from a point to a segment
template <class T>
T getSegDistSq(const geometry::point<T>& p,
const geometry::point<T>& a,
const geometry::point<T>& b) {
auto x = a.x;
auto y = a.y;
auto dx = b.x - x;
auto dy = b.y - y;
if (dx != 0 || dy != 0) {
auto t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x = b.x;
y = b.y;
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}
dx = p.x - x;
dy = p.y - y;
return dx * dx + dy * dy;
}
// signed distance from point to polygon outline (negative if point is outside)
template <class T>
auto pointToPolygonDist(const geometry::point<T>& point, const geometry::polygon<T>& polygon) {
bool inside = false;
auto minDistSq = std::numeric_limits<double>::infinity();
for (const auto& ring : polygon) {
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const auto& a = ring[i];
const auto& b = ring[j];
if ((a.y > point.y) != (b.y > point.y) &&
(point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x)) inside = !inside;
minDistSq = std::min(minDistSq, getSegDistSq(point, a, b));
}
}
return (inside ? 1 : -1) * std::sqrt(minDistSq);
}
template <class T>
struct Cell {
Cell(const geometry::point<T>& c_, T h_, const geometry::polygon<T>& polygon)
: c(c_),
h(h_),
d(pointToPolygonDist(c, polygon)),
max(d + h * std::sqrt(2))
{}
geometry::point<T> c; // cell center
T h; // half the cell size
T d; // distance from cell center to polygon
T max; // max distance to polygon within a cell
};
// get polygon centroid
template <class T>
Cell<T> getCentroidCell(const geometry::polygon<T>& polygon) {
T area = 0;
geometry::point<T> c { 0, 0 };
const auto& ring = polygon.at(0);
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const geometry::point<T>& a = ring[i];
const geometry::point<T>& b = ring[j];
auto f = a.x * b.y - b.x * a.y;
c.x += (a.x + b.x) * f;
c.y += (a.y + b.y) * f;
area += f * 3;
}
return Cell<T>(area == 0 ? ring.at(0) : c / area, 0, polygon);
}
} // namespace detail
template <class T>
geometry::point<T> polylabel(const geometry::polygon<T>& polygon, T precision = 1, bool debug = false) {
using namespace detail;
// find the bounding box of the outer ring
const geometry::box<T> envelope = geometry::envelope(polygon.at(0));
const geometry::point<T> size {
envelope.max.x - envelope.min.x,
envelope.max.y - envelope.min.y
};
const T cellSize = std::min(size.x, size.y);
T h = cellSize / 2;
// a priority queue of cells in order of their "potential" (max distance to polygon)
auto compareMax = [] (const Cell<T>& a, const Cell<T>& b) {
return a.max < b.max;
};
using Queue = std::priority_queue<Cell<T>, std::vector<Cell<T>>, decltype(compareMax)>;
Queue cellQueue(compareMax);
if (cellSize == 0) {
return envelope.min;
}
// cover polygon with initial cells
for (T x = envelope.min.x; x < envelope.max.x; x += cellSize) {
for (T y = envelope.min.y; y < envelope.max.y; y += cellSize) {
cellQueue.push(Cell<T>({x + h, y + h}, h, polygon));
}
}
// take centroid as the first best guess
auto bestCell = getCentroidCell(polygon);
// special case for rectangular polygons
Cell<T> bboxCell(envelope.min + size / 2.0, 0, polygon);
if (bboxCell.d > bestCell.d) {
bestCell = bboxCell;
}
auto numProbes = cellQueue.size();
while (!cellQueue.empty()) {
// pick the most promising cell from the queue
auto cell = cellQueue.top();
cellQueue.pop();
// update the best cell if we found a better one
if (cell.d > bestCell.d) {
bestCell = cell;
if (debug) std::cout << "found best " << ::round(1e4 * cell.d) / 1e4 << " after " << numProbes << " probes" << std::endl;
}
// do not drill down further if there's no chance of a better solution
if (cell.max - bestCell.d <= precision) continue;
// split the cell into four cells
h = cell.h / 2;
cellQueue.push(Cell<T>({cell.c.x - h, cell.c.y - h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x + h, cell.c.y - h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x - h, cell.c.y + h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x + h, cell.c.y + h}, h, polygon));
numProbes += 4;
}
if (debug) {
std::cout << "num probes: " << numProbes << std::endl;
std::cout << "best distance: " << bestCell.d << std::endl;
}
return bestCell.c;
}
} // namespace mapbox
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
// Based on variant/recursive_wrapper.hpp from boost.
//
// Original license:
//
// Copyright (c) 2002-2003
// Eric Friedman, Itay Maman
//
// 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)
#include <cassert>
#include <utility>
namespace mapbox {
namespace util {
template <typename T>
class recursive_wrapper
{
T* p_;
void assign(T const& rhs)
{
this->get() = rhs;
}
public:
using type = T;
/**
* Default constructor default initializes the internally stored value.
* For POD types this means nothing is done and the storage is
* uninitialized.
*
* @throws std::bad_alloc if there is insufficient memory for an object
* of type T.
* @throws any exception thrown by the default constructur of T.
*/
recursive_wrapper()
: p_(new T){};
~recursive_wrapper() noexcept { delete p_; };
recursive_wrapper(recursive_wrapper const& operand)
: p_(new T(operand.get())) {}
recursive_wrapper(T const& operand)
: p_(new T(operand)) {}
recursive_wrapper(recursive_wrapper&& operand)
: p_(new T(std::move(operand.get()))) {}
recursive_wrapper(T&& operand)
: p_(new T(std::move(operand))) {}
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
{
assign(rhs.get());
return *this;
}
inline recursive_wrapper& operator=(T const& rhs)
{
assign(rhs);
return *this;
}
inline void swap(recursive_wrapper& operand) noexcept
{
T* temp = operand.p_;
operand.p_ = p_;
p_ = temp;
}
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
{
swap(rhs);
return *this;
}
recursive_wrapper& operator=(T&& rhs)
{
get() = std::move(rhs);
return *this;
}
T& get()
{
assert(p_);
return *get_pointer();
}
T const& get() const
{
assert(p_);
return *get_pointer();
}
T* get_pointer() { return p_; }
const T* get_pointer() const { return p_; }
operator T const&() const { return this->get(); }
operator T&() { return this->get(); }
}; // class recursive_wrapper
template <typename T>
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
#ifndef MAPBOX_UTIL_VARIANT_HPP
#define MAPBOX_UTIL_VARIANT_HPP
#include <cassert>
#include <cstddef> // size_t
#include <new> // operator new
#include <stdexcept> // runtime_error
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include "recursive_wrapper.hpp"
// clang-format off
// [[deprecated]] is only available in C++14, use this for the time being
#if __cplusplus <= 201103L
# ifdef __GNUC__
# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
# elif defined(_MSC_VER)
# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
# else
# define MAPBOX_VARIANT_DEPRECATED
# endif
#else
# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
#endif
#ifdef _MSC_VER
// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
#ifdef NDEBUG
#define VARIANT_INLINE __forceinline
#else
#define VARIANT_INLINE __declspec(noinline)
#endif
#else
#ifdef NDEBUG
#define VARIANT_INLINE inline __attribute__((always_inline))
#else
#define VARIANT_INLINE __attribute__((noinline))
#endif
#endif
// clang-format on
#define VARIANT_MAJOR_VERSION 1
#define VARIANT_MINOR_VERSION 1
#define VARIANT_PATCH_VERSION 0
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
namespace mapbox {
namespace util {
// XXX This should derive from std::logic_error instead of std::runtime_error.
// See https://github.com/mapbox/variant/issues/48 for details.
class bad_variant_access : public std::runtime_error
{
public:
explicit bad_variant_access(const std::string& what_arg)
: runtime_error(what_arg) {}
explicit bad_variant_access(const char* what_arg)
: runtime_error(what_arg) {}
}; // class bad_variant_access
template <typename R = void>
struct MAPBOX_VARIANT_DEPRECATED static_visitor
{
using result_type = R;
protected:
static_visitor() {}
~static_visitor() {}
};
namespace detail {
static constexpr std::size_t invalid_value = std::size_t(-1);
template <typename T, typename... Types>
struct direct_type;
template <typename T, typename First, typename... Types>
struct direct_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_same<T, First>::value
? sizeof...(Types)
: direct_type<T, Types...>::index;
};
template <typename T>
struct direct_type<T>
{
static constexpr std::size_t index = invalid_value;
};
template <typename T, typename... Types>
struct convertible_type;
template <typename T, typename First, typename... Types>
struct convertible_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_convertible<T, First>::value
? sizeof...(Types)
: convertible_type<T, Types...>::index;
};
template <typename T>
struct convertible_type<T>
{
static constexpr std::size_t index = invalid_value;
};
template <typename T, typename... Types>
struct value_traits
{
using value_type = typename std::remove_reference<T>::type;
static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
static constexpr bool is_direct = direct_index != invalid_value;
static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
static constexpr bool is_valid = index != invalid_value;
static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
};
// check if T is in Types...
template <typename T, typename... Types>
struct has_type;
template <typename T, typename First, typename... Types>
struct has_type<T, First, Types...>
{
static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
};
template <typename T>
struct has_type<T> : std::false_type
{
};
template <typename T, typename... Types>
struct is_valid_type;
template <typename T, typename First, typename... Types>
struct is_valid_type<T, First, Types...>
{
static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
};
template <typename T>
struct is_valid_type<T> : std::false_type
{
};
template <typename T, typename R = void>
struct enable_if_type
{
using type = R;
};
template <typename F, typename V, typename Enable = void>
struct result_of_unary_visit
{
using type = typename std::result_of<F(V&)>::type;
};
template <typename F, typename V>
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
template <typename F, typename V, typename Enable = void>
struct result_of_binary_visit
{
using type = typename std::result_of<F(V&, V&)>::type;
};
template <typename F, typename V>
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
template <std::size_t arg1, std::size_t... others>
struct static_max;
template <std::size_t arg>
struct static_max<arg>
{
static const std::size_t value = arg;
};
template <std::size_t arg1, std::size_t arg2, std::size_t... others>
struct static_max<arg1, arg2, others...>
{
static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
};
template <typename... Types>
struct variant_helper;
template <typename T, typename... Types>
struct variant_helper<T, Types...>
{
VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
{
if (type_index == sizeof...(Types))
{
reinterpret_cast<T*>(data)->~T();
}
else
{
variant_helper<Types...>::destroy(type_index, data);
}
}
VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
{
if (old_type_index == sizeof...(Types))
{
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
}
else
{
variant_helper<Types...>::move(old_type_index, old_value, new_value);
}
}
VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
{
if (old_type_index == sizeof...(Types))
{
new (new_value) T(*reinterpret_cast<const T*>(old_value));
}
else
{
variant_helper<Types...>::copy(old_type_index, old_value, new_value);
}
}
};
template <>
struct variant_helper<>
{
VARIANT_INLINE static void destroy(const std::size_t, void*) {}
VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
};
template <typename T>
struct unwrapper
{
static T const& apply_const(T const& obj) { return obj; }
static T& apply(T& obj) { return obj; }
};
template <typename T>
struct unwrapper<recursive_wrapper<T>>
{
static auto apply_const(recursive_wrapper<T> const& obj)
-> typename recursive_wrapper<T>::type const&
{
return obj.get();
}
static auto apply(recursive_wrapper<T>& obj)
-> typename recursive_wrapper<T>::type&
{
return obj.get();
}
};
template <typename T>
struct unwrapper<std::reference_wrapper<T>>
{
static auto apply_const(std::reference_wrapper<T> const& obj)
-> typename std::reference_wrapper<T>::type const&
{
return obj.get();
}
static auto apply(std::reference_wrapper<T>& obj)
-> typename std::reference_wrapper<T>::type&
{
return obj.get();
}
};
template <typename F, typename V, typename R, typename... Types>
struct dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types>
struct dispatcher<F, V, R, T, Types...>
{
VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
if (v.template is<T>())
{
return f(unwrapper<T>::apply_const(v.template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& v, F&& f)
{
if (v.template is<T>())
{
return f(unwrapper<T>::apply(v.template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T>
struct dispatcher<F, V, R, T>
{
VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
return f(unwrapper<T>::apply_const(v.template get<T>()));
}
VARIANT_INLINE static R apply(V& v, F&& f)
{
return f(unwrapper<T>::apply(v.template get<T>()));
}
};
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_rhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
if (rhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
if (rhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T0, typename T1>
struct binary_dispatcher_rhs<F, V, R, T0, T1>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>()));
}
};
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_lhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
if (lhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
if (lhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>()));
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T0, typename T1>
struct binary_dispatcher_lhs<F, V, R, T0, T1>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>()));
}
};
template <typename F, typename V, typename R, typename... Types>
struct binary_dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher<F, V, R, T, Types...>
{
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
if (v0.template is<T>())
{
if (v1.template is<T>())
{
return f(unwrapper<T>::apply_const(v0.template get<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
}
else if (v1.template is<T>())
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
if (v0.template is<T>())
{
if (v1.template is<T>())
{
return f(unwrapper<T>::apply(v0.template get<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
}
else if (v1.template is<T>())
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
};
template <typename F, typename V, typename R, typename T>
struct binary_dispatcher<F, V, R, T>
{
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
return f(unwrapper<T>::apply_const(v0.template get<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
return f(unwrapper<T>::apply(v0.template get<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
};
// comparator functors
struct equal_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs == rhs;
}
};
struct less_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs < rhs;
}
};
template <typename Variant, typename Comp>
class comparer
{
public:
explicit comparer(Variant const& lhs) noexcept
: lhs_(lhs) {}
comparer& operator=(comparer const&) = delete;
// visitor
template <typename T>
bool operator()(T const& rhs_content) const
{
T const& lhs_content = lhs_.template get<T>();
return Comp()(lhs_content, rhs_content);
}
private:
Variant const& lhs_;
};
// True if Predicate matches for all of the types Ts
template <template <typename> class Predicate, typename... Ts>
struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
std::tuple<typename Predicate<Ts>::type..., std::true_type>>
{
};
// True if Predicate matches for none of the types Ts
template <template <typename> class Predicate, typename... Ts>
struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
std::tuple<typename Predicate<Ts>::type..., std::false_type>>
{
};
} // namespace detail
struct no_init
{
};
template <typename... Types>
class variant
{
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
private:
static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
using data_type = typename std::aligned_storage<data_size, data_align>::type;
using helper_type = detail::variant_helper<Types...>;
std::size_t type_index;
data_type data;
public:
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
: type_index(sizeof...(Types)-1)
{
static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
new (&data) first_type();
}
VARIANT_INLINE variant(no_init) noexcept
: type_index(detail::invalid_value) {}
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
template <typename T, typename Traits = detail::value_traits<T, Types...>,
typename Enable = typename std::enable_if<Traits::is_valid>::type>
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
: type_index(Traits::index)
{
new (&data) typename Traits::target_type(std::forward<T>(val));
}
VARIANT_INLINE variant(variant<Types...> const& old)
: type_index(old.type_index)
{
helper_type::copy(old.type_index, &old.data, &data);
}
VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
: type_index(old.type_index)
{
helper_type::move(old.type_index, &old.data, &data);
}
private:
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::copy(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::move(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
public:
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
{
move_assign(std::move(other));
return *this;
}
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
{
copy_assign(other);
return *this;
}
// conversions
// move-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
{
variant<Types...> temp(std::forward<T>(rhs));
move_assign(std::move(temp));
return *this;
}
// copy-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
{
variant<Types...> temp(rhs);
copy_assign(temp);
return *this;
}
template <typename T>
VARIANT_INLINE bool is() const
{
static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
return type_index == detail::direct_type<T, Types...>::index;
}
VARIANT_INLINE bool valid() const
{
return type_index != detail::invalid_value;
}
template <typename T, typename... Args>
VARIANT_INLINE void set(Args&&... args)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
new (&data) T(std::forward<Args>(args)...);
type_index = detail::direct_type<T, Types...>::index;
}
// get<T>()
template <typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<T, Types...>::index)
{
return *reinterpret_cast<T*>(&data);
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<T, Types...>::index)
{
return *reinterpret_cast<T const*>(&data);
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as recursive_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as std::reference_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// This function is deprecated because it returns an internal index field.
// Use which() instead.
MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
{
return type_index;
}
VARIANT_INLINE int which() const noexcept
{
return static_cast<int>(sizeof...(Types)-type_index - 1);
}
// visitor
// unary
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
auto VARIANT_INLINE static visit(V const& v, F&& f)
-> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
{
return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
auto VARIANT_INLINE static visit(V& v, F&& f)
-> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
{
return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
// binary
// const
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
{
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
// non-const
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
{
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
~variant() noexcept // no-throw destructor
{
helper_type::destroy(type_index, &data);
}
// comparison operators
// equality
VARIANT_INLINE bool operator==(variant const& rhs) const
{
assert(valid() && rhs.valid());
if (this->which() != rhs.which())
{
return false;
}
detail::comparer<variant, detail::equal_comp> visitor(*this);
return visit(rhs, visitor);
}
VARIANT_INLINE bool operator!=(variant const& rhs) const
{
return !(*this == rhs);
}
// less than
VARIANT_INLINE bool operator<(variant const& rhs) const
{
assert(valid() && rhs.valid());
if (this->which() != rhs.which())
{
return this->which() < rhs.which();
}
detail::comparer<variant, detail::less_comp> visitor(*this);
return visit(rhs, visitor);
}
VARIANT_INLINE bool operator>(variant const& rhs) const
{
return rhs < *this;
}
VARIANT_INLINE bool operator<=(variant const& rhs) const
{
return !(*this > rhs);
}
VARIANT_INLINE bool operator>=(variant const& rhs) const
{
return !(*this < rhs);
}
};
// unary visitor interface
// const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
return V::visit(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
return V::visit(v, std::forward<F>(f));
}
// binary visitor interface
// const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
return V::binary_visit(v0, v1, std::forward<F>(f));
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
return V::binary_visit(v0, v1, std::forward<F>(f));
}
// getter interface
template <typename ResultType, typename T>
ResultType& get(T& var)
{
return var.template get<ResultType>();
}
template <typename ResultType, typename T>
ResultType const& get(T const& var)
{
return var.template get<ResultType>();
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_HPP
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
#define MAPBOX_UTIL_VARIANT_IO_HPP
#include <iosfwd>
#include "variant.hpp"
namespace mapbox {
namespace util {
namespace detail {
// operator<< helper
template <typename Out>
class printer
{
public:
explicit printer(Out& out)
: out_(out) {}
printer& operator=(printer const&) = delete;
// visitor
template <typename T>
void operator()(T const& operand) const
{
out_ << operand;
}
private:
Out& out_;
};
}
// operator<<
template <typename CharT, typename Traits, typename... Types>
VARIANT_INLINE std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
{
detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
apply_visitor(visitor, rhs);
return out;
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_IO_HPP
#include <iostream>
#include "snake.h"
#include <clipper.hpp>
#define CLIPPER_SCALE 10000
using namespace snake_geometry;
using namespace std;
namespace bg = boost::geometry;
namespace trans = bg::strategy::transform;
namespace snake {
Scenario::Scenario() :
_mAreaBoundingBox(min_bbox_rt{0, 0, 0, BoostPolygon{}})
{
}
bool Scenario::addArea(Area &area)
{
if (area.geoPolygon.size() < 3){
errorString = "Area has less than three vertices.";
return false;
}
if (area.type == MeasurementArea)
return Scenario::_setMeasurementArea(area);
else if (area.type == ServiceArea)
return Scenario::_setServiceArea(area);
else if (area.type == Corridor)
return Scenario::_setCorridor(area);
return false;
}
bool Scenario::defined(double tileWidth, double tileHeight, double minTileArea)
{
if (!_areas2enu())
return false;
if (!_calculateBoundingBox())
return false;
if (!_calculateTiles(tileWidth, tileHeight, minTileArea))
return false;
if (!_calculateJoinedArea())
return false;
return true;
}
bool Scenario::_areas2enu()
{
if (_measurementArea.geoPolygon.size() > 0){
_measurementAreaENU.clear();
for(auto vertex : _measurementArea.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _measurementArea.altitude}, ENUVertex);
_measurementAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
bg::correct(_measurementAreaENU);
_serviceAreaENU.clear();
if (_serviceArea.geoPolygon.size() > 0){
for(auto vertex : _serviceArea.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _serviceArea.altitude}, ENUVertex);
_serviceAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
} else{
errorString = "Service area has no vertices.";
return false;
}
bg::correct(_serviceAreaENU);
polygonCenter(_serviceAreaENU, _homePositionENU);
_corridorENU.clear();
if (_corridor.geoPolygon.size() > 0){
for(auto vertex : _corridor.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _corridor.altitude}, ENUVertex);
_corridorENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
}
bg::correct(_corridorENU);
return true;
}
errorString = "Measurement area has no vertices.";
return false;
}
bool Scenario::_setMeasurementArea(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
GeoPoint2D origin2D = area.geoPolygon[0];
_geoOrigin = GeoPoint3D{origin2D[0], origin2D[1], 0};
_measurementArea = area;
_measurementAreaENU.clear();
_serviceAreaENU.clear();
_corridorENU.clear();
return true;
}
bool Scenario::_setServiceArea(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
_serviceArea = area;
_serviceAreaENU.clear();
return true;
}
bool Scenario::_setCorridor(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
_corridor = area;
_corridorENU.clear();
return true;
}
bool Scenario::_calculateBoundingBox()
{
minimalBoundingBox(_measurementAreaENU, _mAreaBoundingBox);
return true;
}
/**
* Devides the (measurement area) bounding box into tiles and clips it to the measurement area.
*
* Devides the (measurement area) bounding box into tiles of width \p tileWidth and height \p tileHeight.
* Clips the resulting tiles to the measurement area. Tiles are rejected, if their area is smaller than \p minTileArea.
* The function assumes that \a _measurementAreaENU and \a _mAreaBoundingBox have correct values. \see \ref Scenario::_areas2enu() and \ref
* Scenario::_calculateBoundingBox().
*
* @param tileWidth The width (>0) of a tile.
* @param tileHeight The heigth (>0) of a tile.
* @param minTileArea The minimal area (>0) of a tile.
*
* @return Returns true if successful.
*/
bool Scenario::_calculateTiles(double tileWidth, double tileHeight, double minTileArea)
{
_tilesENU.clear();
_tileCenterPointsENU.clear();
if (tileWidth <= 0 || tileHeight <= 0 || minTileArea <= 0) {
errorString = "Parameters tileWidth, tileHeight, minTileArea must be positive.";
return false;
}
double bbox_width = _mAreaBoundingBox.width;
double bbox_height = _mAreaBoundingBox.height;
BoostPoint origin = _mAreaBoundingBox.corners.outer()[0];
//cout << "Origin: " << origin[0] << " " << origin[1] << endl;
// Transform _measurementAreaENU polygon to bounding box coordinate system.
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(_mAreaBoundingBox.angle*180/M_PI);
trans::translate_transformer<double, 2, 2> translate(-origin.get<0>(), -origin.get<1>());
BoostPolygon translated_polygon;
BoostPolygon rotated_polygon;
boost::geometry::transform(_measurementAreaENU, translated_polygon, translate);
boost::geometry::transform(translated_polygon, rotated_polygon, rotate);
bg::correct(rotated_polygon);
//cout << bg::wkt<BoostPolygon2D>(rotated_polygon) << endl;
size_t i_max = ceil(bbox_width/tileWidth);
size_t j_max = ceil(bbox_height/tileHeight);
if (i_max < 1 || j_max < 1) {
errorString = "tileWidth or tileHeight to small.";
return false;
}
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate_back(-_mAreaBoundingBox.angle*180/M_PI);
trans::translate_transformer<double, 2, 2> translate_back(origin.get<0>(), origin.get<1>());
for (size_t i = 0; i < i_max; ++i){
double x_min = tileWidth*i;
double x_max = x_min + tileWidth;
for (size_t j = 0; j < j_max; ++j){
double y_min = tileHeight*j;
double y_max = y_min + tileHeight;
BoostPolygon tile_unclipped;
tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});
tile_unclipped.outer().push_back(BoostPoint{x_min, y_max});
tile_unclipped.outer().push_back(BoostPoint{x_max, y_max});
tile_unclipped.outer().push_back(BoostPoint{x_max, y_min});
tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});
std::deque<BoostPolygon> boost_tiles;
if (!boost::geometry::intersection(tile_unclipped, rotated_polygon, boost_tiles))
continue;
for (BoostPolygon t : boost_tiles)
{
if (bg::area(t) > minTileArea){
// Transform boost_tile to world coordinate system.
BoostPolygon rotated_tile;
BoostPolygon translated_tile;
boost::geometry::transform(t, rotated_tile, rotate_back);
boost::geometry::transform(rotated_tile, translated_tile, translate_back);
// Store tile and calculate center point.
_tilesENU.push_back(translated_tile);
BoostPoint tile_center;
polygonCenter(translated_tile, tile_center);
_tileCenterPointsENU.push_back(tile_center);
}
}
}
}
if (_tilesENU.size() < 1){
errorString = "No tiles calculated. Is the minTileArea parameter large enough?";
return false;
}
return true;
}
bool Scenario::_calculateJoinedArea()
{
_joinedAreaENU.clear();
// Measurement area and service area overlapping?
bool overlapingSerMeas = bg::intersects(_measurementAreaENU, _serviceAreaENU) ? true : false;
bool corridorValid = _corridorENU.outer().size() > 0 ? true : false;
// Check if corridor is connecting measurement area and service area.
bool corridor_is_connection = false;
if (corridorValid) {
// Corridor overlaping with measurement area?
if ( bg::intersects(_corridorENU, _measurementAreaENU) ) {
// Corridor overlaping with service area?
if ( bg::intersects(_corridorENU, _serviceAreaENU) )
corridor_is_connection = true;
}
}
// Are areas joinable?
std::deque<BoostPolygon> sol;
BoostPolygon partialArea = _measurementAreaENU;
if (overlapingSerMeas){
if(corridor_is_connection){
bg::union_(partialArea, _corridorENU, sol);
}
} else if (corridor_is_connection){
bg::union_(partialArea, _corridorENU, sol);
} else {
errorString = "Areas are not overlapping";
return false;
}
if (sol.size() > 0) {
partialArea = sol[0];
sol.clear();
}
// Join areas.
bg::union_(partialArea, _serviceAreaENU, sol);
if (sol.size() > 0) {
_joinedAreaENU = sol[0];
} else {
return false;
}
return true;
}
FlightPlan::FlightPlan()
{
}
bool FlightPlan::generate(double lineDistance, double minTransectLength)
{
_waypointsENU.clear();
#ifndef NDEBUG
_PathVertices.clear();
#endif
auto start = std::chrono::high_resolution_clock::now();
if (!_generateTransects(lineDistance, minTransectLength))
return false;
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << endl;
cout << "Execution time _generateTransects(): " << delta.count() << " ms" << endl;
//=======================================
// Route Transects using Google or-tools.
//=======================================
// Offset joined area.
const BoostPolygon &jArea = _scenario.getJoineAreaENU();
BoostPolygon jAreaOffset;
offsetPolygon(jArea, jAreaOffset, detail::offsetConstant);
// Create vertex list;
BoostLineString vertices;
size_t n0 = _transects.size()*2+1;
vertices.reserve(n0);
for (auto lstring : _transects){
for (auto vertex : lstring){
vertices.push_back(vertex);
}
}
vertices.push_back(_scenario.getHomePositonENU());
for (long i=0; i<long(jArea.outer().size())-1; ++i) {
vertices.push_back(jArea.outer()[i]);
}
for (auto ring : jArea.inners()) {
for (auto vertex : ring)
vertices.push_back(vertex);
}
size_t n1 = vertices.size();
// Generate routing model.
RoutingDataModel_t dataModel;
Matrix<double> connectionGraph(n1, n1);
start = std::chrono::high_resolution_clock::now();
_generateRoutingModel(vertices, jAreaOffset, n0, dataModel, connectionGraph);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << "Execution time _generateRoutingModel(): " << delta.count() << " ms" << endl;
// Create Routing Index Manager.
RoutingIndexManager manager(dataModel.distanceMatrix.getN(), dataModel.numVehicles,
dataModel.depot);
// Create Routing Model.
RoutingModel routing(manager);
// Create and register a transit callback.
const int transit_callback_index = routing.RegisterTransitCallback(
[&dataModel, &manager](int64 from_index, int64 to_index) -> int64 {
// Convert from routing variable Index to distance matrix NodeIndex.
auto from_node = manager.IndexToNode(from_index).value();
auto to_node = manager.IndexToNode(to_index).value();
return dataModel.distanceMatrix.get(from_node, to_node);
});
// Define Constraints.
size_t n = _transects.size()*2;
Solver *solver = routing.solver();
for (size_t i=0; i<n; i=i+2){
// auto idx0 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i));
// auto idx1 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i+1));
// auto cond0 = routing.NextVar(idx0)->IsEqual(idx1);
// auto cond1 = routing.NextVar(idx1)->IsEqual(idx0);
// auto c = solver->MakeNonEquality(cond0, cond1);
// solver->AddConstraint(c);
// alternative
auto idx0 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i));
auto idx1 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i+1));
auto cond0 = routing.NextVar(idx0)->IsEqual(idx1);
auto cond1 = routing.NextVar(idx1)->IsEqual(idx0);
vector<IntVar*> conds{cond0, cond1};
auto c = solver->MakeAllDifferent(conds);
solver->MakeRejectFilter();
solver->AddConstraint(c);
}
// Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters();
searchParameters.set_first_solution_strategy(
FirstSolutionStrategy::PATH_CHEAPEST_ARC);
google::protobuf::Duration *tMax = new google::protobuf::Duration(); // seconds
tMax->set_seconds(10);
searchParameters.set_allocated_time_limit(tMax);
// Solve the problem.
start = std::chrono::high_resolution_clock::now();
const Assignment* solution = routing.SolveWithParameters(searchParameters);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << "Execution time routing.SolveWithParameters(): " << delta.count() << " ms" << endl;
if (!solution || solution->Size() <= 1){
errorString = "Not able to solve the routing problem.";
return false;
}
// Extract waypoints from solution.
long index = routing.Start(0);
std::vector<size_t> route;
route.push_back(manager.IndexToNode(index).value());
while (!routing.IsEnd(index)){
index = solution->Value(routing.NextVar(index));
route.push_back(manager.IndexToNode(index).value());
}
// Connect transects
#ifndef NDEBUG
_PathVertices = vertices;
#endif
{
_waypointsENU.push_back(vertices[route[0]]);
vector<size_t> pathIdx;
for (long i=0; i<long(route.size())-1; ++i){
size_t idx0 = route[i];
size_t idx1 = route[i+1];
pathIdx.clear();
shortestPathFromGraph(connectionGraph, idx0, idx1, pathIdx);
for (size_t j=1; j<pathIdx.size(); ++j)
_waypointsENU.push_back(vertices[pathIdx[j]]);
}
}
return true;
}
bool FlightPlan::_generateTransects(double lineDistance, double minTransectLength)
{
_transects.clear();
if (_scenario.getTilesENU().size() != _progress.size()){
errorString = "Number of tiles is not equal to progress array length";
return false;
}
// Calculate processed tiles (_progress[i] == 100) and subtract them from measurement area.
size_t num_tiles = _progress.size();
vector<BoostPolygon> processedTiles;
{
const auto &tiles = _scenario.getTilesENU();
for (size_t i=0; i<num_tiles; ++i) {
if (_progress[i] == 100){
processedTiles.push_back(tiles[i]);
}
}
if (processedTiles.size() == num_tiles)
return true;
}
// Convert measurement area and tiles to clipper path.
ClipperLib::Path mAreaClipper;
for ( auto vertex : _scenario.getMeasurementAreaENU().outer() ){
mAreaClipper.push_back(ClipperLib::IntPoint{static_cast<ClipperLib::cInt>(vertex.get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>()*CLIPPER_SCALE)});
}
vector<ClipperLib::Path> processedTilesClipper;
for (auto t : processedTiles){
ClipperLib::Path path;
for (auto vertex : t.outer()){
path.push_back(ClipperLib::IntPoint{static_cast<ClipperLib::cInt>(vertex.get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>()*CLIPPER_SCALE)});
}
processedTilesClipper.push_back(path);
}
const min_bbox_rt &bbox = _scenario.getMeasurementAreaBBoxENU();
double alpha = bbox.angle;
double x0 = bbox.corners.outer()[0].get<0>();
double y0 = bbox.corners.outer()[0].get<1>();
double bboxWidth = bbox.width;
double bboxHeight = bbox.height;
double delta = detail::offsetConstant;
size_t num_t = int(ceil((bboxHeight + 2*delta)/lineDistance)); // number of transects
vector<double> yCoords;
yCoords.reserve(num_t);
double y = -delta;
for (size_t i=0; i < num_t; ++i) {
yCoords.push_back(y);
y += lineDistance;
}
// Generate transects and convert them to clipper path.
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate_back(-alpha*180/M_PI);
trans::translate_transformer<double, 2, 2> translate_back(x0, y0);
vector<ClipperLib::Path> transectsClipper;
transectsClipper.reserve(num_t);
for (size_t i=0; i < num_t; ++i) {
// calculate transect
BoostPoint v1{-delta, yCoords[i]};
BoostPoint v2{bboxWidth+delta, yCoords[i]};
BoostLineString transect;
transect.push_back(v1);
transect.push_back(v2);
// transform back
BoostLineString temp_transect;
bg::transform(transect, temp_transect, rotate_back);
transect.clear();
bg::transform(temp_transect, transect, translate_back);
ClipperLib::IntPoint c1{static_cast<ClipperLib::cInt>(transect[0].get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(transect[0].get<1>()*CLIPPER_SCALE)};
ClipperLib::IntPoint c2{static_cast<ClipperLib::cInt>(transect[1].get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(transect[1].get<1>()*CLIPPER_SCALE)};
ClipperLib::Path path{c1, c2};
transectsClipper.push_back(path);
}
// Perform clipping.
// Clip transects to measurement area.
ClipperLib::Clipper clipper;
clipper.AddPath(mAreaClipper, ClipperLib::ptClip, true);
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
ClipperLib::PolyTree clippedTransecsPolyTree1;
clipper.Execute(ClipperLib::ctIntersection, clippedTransecsPolyTree1, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes (tiles with measurement_progress == 100) from transects.
clipper.Clear();
for (auto child : clippedTransecsPolyTree1.Childs)
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
clipper.AddPaths(processedTilesClipper, ClipperLib::ptClip, true);
ClipperLib::PolyTree clippedTransecsPolyTree2;
clipper.Execute(ClipperLib::ctDifference, clippedTransecsPolyTree2, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Extract transects from PolyTree and convert them to BoostLineString
for (auto child : clippedTransecsPolyTree2.Childs){
ClipperLib::Path clipperTransect = child->Contour;
BoostPoint v1{static_cast<double>(clipperTransect[0].X)/CLIPPER_SCALE,
static_cast<double>(clipperTransect[0].Y)/CLIPPER_SCALE};
BoostPoint v2{static_cast<double>(clipperTransect[1].X)/CLIPPER_SCALE,
static_cast<double>(clipperTransect[1].Y)/CLIPPER_SCALE};
BoostLineString transect{v1, v2};
if (bg::length(transect) >= minTransectLength)
_transects.push_back(transect);
}
if (_transects.size() < 1)
return false;
return true;
}
void FlightPlan::_generateRoutingModel(const BoostLineString &vertices,
const BoostPolygon &polygonOffset,
size_t n0,
FlightPlan::RoutingDataModel_t &dataModel,
Matrix<double> &graph)
{
auto start = std::chrono::high_resolution_clock::now();
graphFromPolygon(polygonOffset, vertices, graph);
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start);
cout << "Execution time graphFromPolygon(): " << delta.count() << " ms" << endl;
// cout << endl;
// for (size_t i=0; i<graph.size(); ++i){
// vector<double> &row = graph[i];
// for (size_t j=0; j<row.size();++j){
// cout << "(" << i << "," << j << "):" << row[j] << " ";
// }
// cout << endl;
// }
// cout << endl;
Matrix<double> distanceMatrix(graph);
start = std::chrono::high_resolution_clock::now();
toDistanceMatrix(distanceMatrix);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start);
cout << "Execution time toDistanceMatrix(): " << delta.count() << " ms" << endl;
dataModel.distanceMatrix.setDimension(n0, n0);
for (size_t i=0; i<n0; ++i){
dataModel.distanceMatrix.set(i, i, 0);
for (size_t j=i+1; j<n0; ++j){
dataModel.distanceMatrix.set(i, j, int64_t(distanceMatrix.get(i, j)*CLIPPER_SCALE));
dataModel.distanceMatrix.set(j, i, int64_t(distanceMatrix.get(i, j)*CLIPPER_SCALE));
}
}
dataModel.numVehicles = 1;
dataModel.depot = n0-1;
}
}
#pragma once
#include <vector>
#include <string>
#include <array>
#include "snake_geometry.h"
#include "ortools/constraint_solver/routing.h"
#include "ortools/constraint_solver/routing_enums.pb.h"
#include "ortools/constraint_solver/routing_index_manager.h"
#include "ortools/constraint_solver/routing_parameters.h"
using namespace std;
using namespace snake_geometry;
using namespace operations_research;
namespace snake {
enum AreaType {MeasurementArea, ServiceArea, Corridor};
struct Area {
GeoPoint2DList geoPolygon;
double altitude;
size_t layers;
AreaType type;
};
//========================================================================================
// Scenario
//========================================================================================
class Scenario{
public:
Scenario();
bool addArea(Area &area);
const Area &getMeasurementArea() const {return _measurementArea;}
const Area &getServiceArea() const {return _serviceArea;}
const Area &getCorridor() const {return _corridor;}
const BoostPolygon &getMeasurementAreaENU() {return _measurementAreaENU;}
const BoostPolygon &getServiceAreaENU() {return _serviceAreaENU;}
const BoostPolygon &getCorridorENU() {return _corridorENU;}
const BoostPolygon &getJoineAreaENU() {return _joinedAreaENU;}
const GeoPoint3D &getOrigin() {return _geoOrigin;}
const vector<BoostPolygon> &getTilesENU() {return _tilesENU;}
const BoostLineString &getTileCenterPointsENU() {return _tileCenterPointsENU;}
const min_bbox_rt &getMeasurementAreaBBoxENU() {return _mAreaBoundingBox;}
const BoostPoint &getHomePositonENU() {return _homePositionENU;}
bool defined(double tileWidth, double tileHeight, double minTileArea);
string errorString;
private:
bool _areas2enu();
bool _setMeasurementArea(Area &area);
bool _setServiceArea(Area &area);
bool _setCorridor(Area &area);
bool _calculateBoundingBox();
bool _calculateTiles(double tileWidth, double tileHeight, double minTileArea);
bool _calculateJoinedArea();
Area _measurementArea;
Area _serviceArea;
Area _corridor;
BoostPolygon _measurementAreaENU;
BoostPolygon _serviceAreaENU;
BoostPolygon _corridorENU;
BoostPolygon _joinedAreaENU;
min_bbox_rt _mAreaBoundingBox;
vector<BoostPolygon> _tilesENU;
BoostLineString _tileCenterPointsENU;
GeoPoint3D _geoOrigin;
BoostPoint _homePositionENU;
};
//========================================================================================
// FlightPlan
//========================================================================================
class FlightPlan{
public:
FlightPlan();
void setScenario(const Scenario &scenario) {_scenario = scenario;}
void setProgress(const vector<int8_t> &progress) {_progress = progress;}
const Scenario &getScenario(void) const {return _scenario;}
const BoostLineString &getWaypointsENU(void) const {return _waypointsENU;}
const GeoPoint2DList &getWaypoints(void) const {return _waypoints;}
#ifndef NDEBUG
const BoostLineString &getPathVertices(void) const {return _PathVertices;}
#endif
bool generate(double lineDistance, double minTransectLength);
const vector<BoostLineString> &getTransects() const {return _transects;}
string errorString;
private:
// Search Filter to speed up routing.SolveWithParameters(...);
// Found here: http://www.lia.disi.unibo.it/Staff/MicheleLombardi/or-tools-doc/user_manual/manual/ls/ls_filtering.html
class SearchFilter : public LocalSearchFilter{
};
typedef struct{
Matrix<int64_t> distanceMatrix;
long numVehicles;
RoutingIndexManager::NodeIndex depot;
}RoutingDataModel_t;
bool _generateTransects(double lineDistance, double minTransectLength);
void _generateRoutingModel(const BoostLineString &vertices,
const BoostPolygon &polygonOffset,
size_t n0,
RoutingDataModel_t &dataModel,
Matrix<double> &graph);
Scenario _scenario;
BoostLineString _waypointsENU;
GeoPoint2DList _waypoints;
vector<BoostLineString> _transects;
vector<int8_t> _progress;
#ifndef NDEBUG
BoostLineString _PathVertices;
#endif
};
namespace detail {
const double offsetConstant = 0.1; // meter, polygon offset to compenstate for numerical inaccurracies.
}
}
#include "snake_geometry.h"
#include <mapbox/polylabel.hpp>
#include <mapbox/geometry.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <GeographicLib/Geocentric.hpp>
#include <GeographicLib/LocalCartesian.hpp>
using namespace mapbox;
using namespace snake_geometry;
using namespace std;
namespace bg = bg;
namespace trans = bg::strategy::transform;
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
namespace snake_geometry {
void toENU(const GeoPoint3D &WGS84Reference, const GeoPoint3D &WGS84Position, Point3D &ENUPosition)
{
GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f());
GeographicLib::LocalCartesian proj(WGS84Reference[0], WGS84Reference[1], WGS84Reference[2], earth);
proj.Forward(WGS84Position[0], WGS84Position[1], WGS84Position[2], ENUPosition[0], ENUPosition[1], ENUPosition[2]);
}
void fromENU(const Point3D &WGS84Reference, const Point3D &CartesianPosition, GeoPoint3D &GeoPosition)
{
GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f());
GeographicLib::LocalCartesian proj(WGS84Reference[0], WGS84Reference[1], WGS84Reference[2], earth);
proj.Reverse(CartesianPosition[0], CartesianPosition[1], CartesianPosition[2], GeoPosition[0], GeoPosition[1], GeoPosition[2]);
}
void polygonCenter(const BoostPolygon &polygon, BoostPoint &center)
{
if (polygon.outer().empty())
return;
geometry::polygon<double> p;
geometry::linear_ring<double> lr1;
for (size_t i = 0; i < polygon.outer().size(); ++i) {
geometry::point<double> vertex(polygon.outer()[i].get<0>(), polygon.outer()[i].get<1>());
lr1.push_back(vertex);
}
p.push_back(lr1);
geometry::point<double> c = polylabel(p);
center.set<0>(c.x);
center.set<1>(c.y);
}
void minimalBoundingBox(const BoostPolygon &polygon, min_bbox_rt &minBBox)
{
/*
Find the minimum-area bounding box of a set of 2D points
The input is a 2D convex hull, in an Nx2 numpy array of x-y co-ordinates.
The first and last points points must be the same, making a closed polygon.
This program finds the rotation angles of each edge of the convex polygon,
then tests the area of a bounding box aligned with the unique angles in
90 degrees of the 1st Quadrant.
Returns the
Tested with Python 2.6.5 on Ubuntu 10.04.4 (original version)
Results verified using Matlab
Copyright (c) 2013, David Butterworth, University of Queensland
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Willow Garage, Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
if (polygon.outer().empty())
return;
BoostPolygon convex_hull;
bg::convex_hull(polygon, convex_hull);
//cout << "Convex hull: " << bg::wkt<BoostPolygon2D>(convex_hull) << endl;
//# Compute edges (x2-x1,y2-y1)
std::vector<BoostPoint> edges;
auto convex_hull_outer = convex_hull.outer();
for (long i=0; i < long(convex_hull_outer.size())-1; ++i) {
BoostPoint p1 = convex_hull_outer.at(i);
BoostPoint p2 = convex_hull_outer.at(i+1);
double edge_x = p2.get<0>() - p1.get<0>();
double edge_y = p2.get<1>() - p1.get<1>();
edges.push_back(BoostPoint{edge_x, edge_y});
}
// cout << "Edges: ";
// for (auto e : edges)
// cout << e.get<0>() << " " << e.get<1>() << ",";
// cout << endl;
// Calculate unique edge angles atan2(y/x)
double angle_scale = 1e3;
std::set<long> angles_long;
for (auto vertex : edges) {
double angle = std::fmod(atan2(vertex.get<1>(), vertex.get<0>()), M_PI / 2);
angle = angle < 0 ? angle + M_PI / 2 : angle; // want strictly positive answers
angles_long.insert(long(round(angle*angle_scale)));
}
std::vector<double> edge_angles;
for (auto a : angles_long)
edge_angles.push_back(double(a)/angle_scale);
// cout << "Unique angles: ";
// for (auto e : edge_angles)
// cout << e*180/M_PI << ",";
// cout << endl;
double min_area = std::numeric_limits<double>::infinity();
// Test each angle to find bounding box with smallest area
// print "Testing", len(edge_angles), "possible rotations for bounding box... \n"
for (double angle : edge_angles){
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(angle*180/M_PI);
BoostPolygon hull_rotated;
bg::transform(convex_hull, hull_rotated, rotate);
//cout << "Convex hull rotated: " << bg::wkt<BoostPolygon2D>(hull_rotated) << endl;
bg::model::box<BoostPoint> box;
bg::envelope(hull_rotated, box);
// cout << "Bounding box: " << bg::wkt<bg::model::box<BoostPoint2D>>(box) << endl;
//# print "Rotated hull points are \n", rot_points
BoostPoint min_corner = box.min_corner();
BoostPoint max_corner = box.max_corner();
double min_x = min_corner.get<0>();
double max_x = max_corner.get<0>();
double min_y = min_corner.get<1>();
double max_y = max_corner.get<1>();
// cout << "min_x: " << min_x << endl;
// cout << "max_x: " << max_x << endl;
// cout << "min_y: " << min_y << endl;
// cout << "max_y: " << max_y << endl;
// Calculate height/width/area of this bounding rectangle
double width = max_x - min_x;
double height = max_y - min_y;
double area = width * height;
// cout << "Width: " << width << endl;
// cout << "Height: " << height << endl;
// cout << "area: " << area << endl;
// cout << "angle: " << angle*180/M_PI << endl;
// Store the smallest rect found first (a simple convex hull might have 2 answers with same area)
if (area < min_area){
min_area = area;
minBBox.angle = angle;
minBBox.width = width;
minBBox.height = height;
minBBox.corners.clear();
minBBox.corners.outer().push_back(BoostPoint{min_x, min_y});
minBBox.corners.outer().push_back(BoostPoint{min_x, max_y});
minBBox.corners.outer().push_back(BoostPoint{max_x, max_y});
minBBox.corners.outer().push_back(BoostPoint{max_x, min_y});
minBBox.corners.outer().push_back(BoostPoint{min_x, min_y});
}
//cout << endl << endl;
}
// Transform corners of minimal bounding box.
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(-minBBox.angle*180/M_PI);
BoostPolygon rotated_polygon;
bg::transform(minBBox.corners, rotated_polygon, rotate);
minBBox.corners = rotated_polygon;
}
void toBoost(const Point2D &point, BoostPoint &boost_point)
{
boost_point.set<0>(point[0]);
boost_point.set<1>(point[1]);
}
void fromBoost(const BoostPoint &boost_point, Point2D &point)
{
point[0] = boost_point.get<0>();
point[1] = boost_point.get<1>();
}
void toBoost(const Point2DList &point_list, BoostPolygon &boost_polygon)
{
for (auto vertex : point_list) {
BoostPoint boost_vertex;
toBoost(vertex, boost_vertex);
boost_polygon.outer().push_back(boost_vertex);
}
bg::correct(boost_polygon);
}
void fromBoost(const BoostPolygon &boost_polygon, Point2DList &point_list)
{
for (auto boost_vertex : boost_polygon.outer()) {
Point2D vertex;
fromBoost(boost_vertex, vertex);
point_list.push_back(vertex);
}
}
void rotateDeg(const Point2DList &point_list, Point2DList &rotated_point_list, double degree)
{
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(degree);
BoostPolygon boost_polygon;
toBoost(point_list, boost_polygon);
BoostPolygon rotated_polygon;
bg::transform(boost_polygon, rotated_polygon, rotate);
fromBoost(rotated_polygon, rotated_point_list);
}
void rotateRad(const Point2DList &point_list, Point2DList &rotated_point_list, double rad)
{
rotateDeg(point_list, rotated_point_list, rad*180/M_PI);
}
bool isClockwise(const Point2DList &point_list)
{
double orientaion = 0;
double len = point_list.size();
for (long i=0; i < len-1; ++i){
Point2D v1 = point_list[i];
Point2D v2 = point_list[i+1];
orientaion += (v2[0]-v1[0])*(v2[1]+v1[1]);
}
Point2D v1 = point_list[len-1];
Point2D v2 = point_list[0];
orientaion += (v2[0]-v1[0])*(v2[1]+v1[1]);
return orientaion > 0 ? true : false;
}
void offsetPolygon(const BoostPolygon &polygon, BoostPolygon &polygonOffset, double offset)
{
bg::strategy::buffer::distance_symmetric<double> distance_strategy(offset);
bg::strategy::buffer::join_miter join_strategy(3);
bg::strategy::buffer::end_flat end_strategy;
bg::strategy::buffer::point_square point_strategy;
bg::strategy::buffer::side_straight side_strategy;
bg::model::multi_polygon<BoostPolygon> result;
bg::buffer(polygon, result, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy);
polygonOffset = result[0];
}
void graphFromPolygon(const BoostPolygon &polygon, const BoostLineString &vertices, Matrix<double> &graph)
{
size_t n = graph.getN();
for (size_t i=0; i < n; ++i) {
BoostPoint v1 = vertices[i];
for (size_t j=i+1; j < n; ++j){
BoostPoint v2 = vertices[j];
BoostLineString path{v1, v2};
double distance = 0;
if (!bg::within(path, polygon))
distance = std::numeric_limits<double>::infinity();
else
distance = bg::length(path);
graph.set(i, j, distance);
graph.set(j, i, distance);
}
}
}
bool dijkstraAlgorithm(const size_t numElements,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &elementPath,
std::function<double (const size_t, const size_t)> distanceDij)
{
if ( numElements < 0
|| startIndex < 0
|| endIndex < 0
|| startIndex >= numElements
|| endIndex >= numElements
|| endIndex == startIndex) {
return false;
}
// Node struct
// predecessorIndex is the index of the predecessor node (nodeList[predecessorIndex])
// distance is the distance between the node and the start node
// node number is stored by the position in nodeList
struct Node{
int predecessorIndex = -1;
double distance = std::numeric_limits<double>::infinity();
};
// The list with all Nodes (elements)
std::vector<Node> nodeList(numElements);
// This list will be initalized with indices referring to the elements of nodeList.
// Elements will be successively remove during the execution of the Dijkstra Algorithm.
std::vector<size_t> workingSet(numElements);
//append elements to node list
for (size_t i = 0; i < numElements; ++i) workingSet[i] = i;
nodeList[startIndex].distance = 0;
// Dijkstra Algorithm
// https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
while (workingSet.size() > 0) {
// serach Node with minimal distance
double minDist = std::numeric_limits<double>::infinity();
int minDistIndex_WS = -1; // WS = workinSet
for (size_t i = 0; i < workingSet.size(); ++i) {
const int nodeIndex = workingSet.at(i);
const double dist = nodeList.at(nodeIndex).distance;
if (dist < minDist) {
minDist = dist;
minDistIndex_WS = i;
}
}
if (minDistIndex_WS == -1)
return false;
size_t indexU_NL = workingSet.at(minDistIndex_WS); // NL = nodeList
workingSet.erase(workingSet.begin()+minDistIndex_WS);
if (indexU_NL == endIndex) // shortest path found
break;
const double distanceU = nodeList.at(indexU_NL).distance;
//update distance
for (size_t i = 0; i < workingSet.size(); ++i) {
int indexV_NL = workingSet[i]; // NL = nodeList
Node* v = &nodeList[indexV_NL];
double dist = distanceDij(indexU_NL, indexV_NL);
// is ther an alternative path which is shorter?
double alternative = distanceU + dist;
if (alternative < v->distance) {
v->distance = alternative;
v->predecessorIndex = indexU_NL;
}
}
}
// end Djikstra Algorithm
// reverse assemble path
int e = endIndex;
while (1) {
if (e == -1) {
if (elementPath[0] == startIndex)// check if starting point was reached
break;
return false;
}
elementPath.insert(elementPath.begin(), e);
//Update Node
e = nodeList[e].predecessorIndex;
}
return true;
}
void toDistanceMatrix(Matrix<double> &graph)
{
size_t n = graph.getN();
auto distance = [graph](size_t i, size_t j){
return graph.get(i,j);
};
std::vector<size_t> path;
for (size_t i=0; i < n; ++i) {
for (size_t j=i+1; j < n; ++j){
double d = graph.get(i,j);
if (!std::isinf(d))
continue;
path.clear();
bool ret = dijkstraAlgorithm(n, i, j, path, distance);
assert(ret);
(void)ret;
// cout << "(" << i << "," << j << ") d: " << d << endl;
// cout << "Path size: " << path.size() << endl;
// for (auto idx : path)
// cout << idx << " ";
// cout << endl;
d = 0;
for (long k=0; k < long(path.size())-1; ++k) {
size_t idx0 = path[k];
size_t idx1 = path[k+1];
double d0 = graph.get(idx0, idx1);
assert(std::isinf(d0) == false);
d += d0;
}
graph.set(i, j, d);
graph.set(j, i, d);
}
}
}
void shortestPathFromGraph(const Matrix<double> &graph, size_t startIndex, size_t endIndex, std::vector<size_t> &pathIdx)
{
if (!std::isinf(graph.get(startIndex, endIndex))){
pathIdx.push_back(startIndex);
pathIdx.push_back(endIndex);
} else {
auto distance = [graph](size_t i, size_t j){
return graph.get(i, j);
};
bool ret = dijkstraAlgorithm(graph.getN(), startIndex, endIndex, pathIdx, distance);
assert(ret);
(void)ret;
}
}
} // end namespace snake_geometry
#pragma once
#include <vector>
#include <array>
#include <boost/geometry.hpp>
#include <bits/stl_set.h>
namespace bg = boost::geometry;
namespace snake_geometry {
typedef std::array<double, 3> Point2D;
typedef std::array<double, 3> Point3D;
typedef std::array<double, 3> GeoPoint3D;
typedef std::array<double, 2> GeoPoint2D;
typedef std::vector<Point2D> Point2DList;
typedef std::vector<Point3D> Point3DList;
typedef std::vector<GeoPoint2D> GeoPoint2DList;
typedef std::vector<GeoPoint3D> GeoPoint3DList;
typedef bg::model::point<double, 2, bg::cs::cartesian> BoostPoint;
//typedef std::vector<BoostPoint> BoostPointList;
typedef bg::model::polygon<BoostPoint> BoostPolygon;
typedef bg::model::linestring<BoostPoint> BoostLineString;
typedef std::vector<std::vector<int64_t>> Int64Matrix;
template<class T>
class Matrix{
public:
Matrix() :
_elements(0),
_m(0),
_n(0),
_isInitialized(false)
{
}
Matrix(size_t m, size_t n) : Matrix(m, n, T{0}){}
Matrix(size_t m, size_t n, T value) :
_elements(m*n),
_m(m),
_n(n),
_isInitialized(true)
{
assert((m > 0) || (n > 0));
_matrix.resize(_elements, value);
}
double get(size_t i, size_t j) const
{
assert(_isInitialized);
assert(i < _m);
assert(j < _n);
return _matrix[i*_m+j];
}
size_t getM() const { return _m;}
size_t getN() const { return _n;}
void set(size_t i, size_t j, const T &value)
{
assert(_isInitialized);
assert(i < _m);
assert(j < _n);
_matrix[i*_m+j] = value;
}
void setDimension(size_t m, size_t n, const T &value)
{
assert((m > 0) || (n > 0));
assert(!_isInitialized);
if (!_isInitialized){
_m = m;
_n = n;
_elements = n*m;
_matrix.resize(_elements, value);
}
}
void setDimension(size_t m, size_t n)
{
assert((m > 0) || (n > 0));
assert(!_isInitialized);
if (!_isInitialized){
_m = m;
_n = n;
_elements = n*m;
_matrix.resize(_elements);
}
}
private:
size_t _elements;
size_t _m;
size_t _n;
bool _isInitialized;
std::vector<T> _matrix;
};
typedef struct {
double width;
double height;
double angle;
BoostPolygon corners;
}min_bbox_rt;
void toENU(const GeoPoint3D &WGS84Reference, const GeoPoint3D &WGS84Position, Point3D &ENUPosition);
void fromENU(const Point3D &WGS84Reference, const Point3D &ENUPosition, GeoPoint3D &WGS84Position);
void polygonCenter(const BoostPolygon &polygon, BoostPoint &center);
void minimalBoundingBox(const BoostPolygon &polygon, min_bbox_rt &minBBox);
void offsetPolygon(const BoostPolygon &polygon, BoostPolygon &polygonOffset, double offset);
void graphFromPolygon(const BoostPolygon &polygon, const BoostLineString &vertices, Matrix<double> &graph);
void toDistanceMatrix(Matrix<double> &graph);
bool dijkstraAlgorithm(const size_t numElements,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &elementPath,
std::function<double (const size_t, const size_t)> distanceDij);
void shortestPathFromGraph(const Matrix<double> &graph,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &pathIdx);
void rotateDeg(const Point2DList &point_list, Point2DList &rotated_point_list, double degree);
void rotateRad(const Point2DList &point_list, Point2DList &rotated_point_list, double rad);
bool isClockwise(const Point2DList &point_list);
void toBoost(const Point2D &point, BoostPoint &boost_point);
void toBoost(const Point2DList &point_list, BoostPolygon &boost_polygon);
void fromBoost(const BoostPoint &boost_point, Point2D &point);
void fromBoost(const BoostPolygon &boost_polygon, Point2DList &point_list);
}
#include <chrono>
#include <iostream>
#include <fstream>
#include <time.h>
#include "snake.h"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include "catch.hpp"
using namespace snake;
using namespace std;
//===========================================================================================
// Scenario
//===========================================================================================
TEST_CASE( "Test Scenario Class, check out Scenario0.svg" ) {
// Data
Area measurementArea{GeoPoint2DList{GeoPoint2D{47.768120, 16.530380},
GeoPoint2D{47.768205, 16.530558},
GeoPoint2D{47.768147, 16.530566},
GeoPoint2D{47.768326, 16.530926},
GeoPoint2D{47.768135, 16.531025},
GeoPoint2D{47.768144, 16.530845},
GeoPoint2D{47.768103, 16.530978},
GeoPoint2D{47.767940, 16.530393}},
10, /*altitude*/
1, /*layers*/
AreaType::MeasurementArea};
Area serviceArea{GeoPoint2DList{GeoPoint2D{47.767874, 16.530409},
GeoPoint2D{47.767968, 16.530677},
GeoPoint2D{47.767860, 16.530723},
GeoPoint2D{47.767777, 16.530447}},
10, /*altitude*/
1, /*layers*/
AreaType::ServiceArea};
Area corridor{GeoPoint2DList{GeoPoint2D{47.767853, 16.530482},
GeoPoint2D{47.768004, 16.530382},
GeoPoint2D{47.768035, 16.530549},
GeoPoint2D{47.767880, 16.530629}},
10, /*altitude*/
1, /*layers*/
AreaType::Corridor};
Scenario scenario;
scenario.addArea(measurementArea);
scenario.addArea(serviceArea);
scenario.addArea(corridor);
// Scenario defined?
double tileWidth = 3; // m
double tileHeight = 3; // m
double minTileArea = 2; // m^2
auto start = std::chrono::high_resolution_clock::now();
scenario.defined(tileWidth, tileHeight, minTileArea);
cout << "Execution time scenario.defined(): ";
cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start).count();
cout << " ms" << endl;
// Store to svg.
std::ofstream svg("Scenario0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 400, 400);
const BoostPolygon &boost_measurement_area = scenario.getMeasurementAreaENU();
const BoostPolygon &boost_service_area = scenario.getServiceAreaENU();
const BoostPolygon &boost_corridor_area = scenario.getCorridorENU();
const BoostPolygon &boos_joined_area = scenario.getJoineAreaENU();
const BoostPolygon &boost_bbox = scenario.getMeasurementAreaBBoxENU().corners;
mapper.add(boost_measurement_area);
mapper.add(boost_service_area);
mapper.add(boost_corridor_area);
mapper.add(boos_joined_area);
mapper.add(boost_bbox);
mapper.map(boost_measurement_area, "fill-opacity:0.1;fill:rgb(0,255,0);stroke:rgb(0,255,0);stroke-width:2");
mapper.map(boost_service_area, "fill-opacity:0.1;fill:rgb(235, 232, 52);stroke:rgb(235, 232, 52);stroke-width:2");
mapper.map(boost_corridor_area, "fill-opacity:0.1;fill:rgb(52, 171, 235);stroke:rgb(52, 171, 235);stroke-width:2");
mapper.map(boos_joined_area, "fill-opacity:0.0;fill:rgb(245, 66, 218);stroke:rgb(245, 66, 218);stroke-width:3");
mapper.map(boost_bbox, "fill-opacity:0.0;fill:rgb(255, 55, 0);stroke:rgb(255, 55, 0);stroke-width:2");
auto tiles = scenario.getTilesENU();
//cout << "Tile count: " << tiles.size() << endl;
for (auto tile : tiles) {
mapper.add(tile);
mapper.map(tile, "fill-opacity:0.1;fill:rgb(0,0,0);stroke:rgb(0,0,0);stroke-width:2");
}
auto center_points = scenario.getTileCenterPointsENU();
for (auto point : center_points) {
mapper.add(point);
mapper.map(point, "fill-opacity:0.5;fill:rgb(255, 55, 0);stroke:rgb(255, 55, 0);stroke-width:2", 2);
}
REQUIRE(scenario.defined(tileWidth, tileHeight, minTileArea));
//cout << scenario.errorString;
}
TEST_CASE( "Test Scenario Class. Negative Parameter." ) {
// Data
Area measurementArea{GeoPoint2DList{GeoPoint2D{47.768120, 16.530380},
GeoPoint2D{47.768205, 16.530558},
GeoPoint2D{47.768147, 16.530566},
GeoPoint2D{47.768326, 16.530926},
GeoPoint2D{47.768135, 16.531025},
GeoPoint2D{47.768144, 16.530845},
GeoPoint2D{47.768103, 16.530978},
GeoPoint2D{47.767940, 16.530393}},
10, /*altitude*/
1, /*layers*/
AreaType::MeasurementArea};
Area serviceArea{GeoPoint2DList{GeoPoint2D{47.767874, 16.530409},
GeoPoint2D{47.767968, 16.530677},
GeoPoint2D{47.767860, 16.530723},
GeoPoint2D{47.767777, 16.530447}},
10, /*altitude*/
1, /*layers*/
AreaType::ServiceArea};
Area corridor{GeoPoint2DList{GeoPoint2D{47.767853, 16.530482},
GeoPoint2D{47.768004, 16.530382},
GeoPoint2D{47.768035, 16.530549},
GeoPoint2D{47.767880, 16.530629}},
10, /*altitude*/
1, /*layers*/
AreaType::Corridor};
Scenario scenario;
scenario.addArea(measurementArea);
scenario.addArea(serviceArea);
scenario.addArea(corridor);
// Scenario defined?
double tileWidth = 5; // m
double tileHeight = 5; // m
double minTileArea = -2; // m^2
REQUIRE(scenario.defined(tileWidth, tileHeight, minTileArea) == false);
}
TEST_CASE( "Test Scenario Class. Missing Corridor." ) {
// Data
Area measurementArea{GeoPoint2DList{GeoPoint2D{47.768120, 16.530380},
GeoPoint2D{47.768205, 16.530558},
GeoPoint2D{47.768147, 16.530566},
GeoPoint2D{47.768326, 16.530926},
GeoPoint2D{47.768135, 16.531025},
GeoPoint2D{47.768144, 16.530845},
GeoPoint2D{47.768103, 16.530978},
GeoPoint2D{47.767940, 16.530393}},
10, /*altitude*/
1, /*layers*/
AreaType::MeasurementArea};
Area serviceArea{GeoPoint2DList{GeoPoint2D{47.767874, 16.530409},
GeoPoint2D{47.767968, 16.530677},
GeoPoint2D{47.767860, 16.530723},
GeoPoint2D{47.767777, 16.530447}},
10, /*altitude*/
1, /*layers*/
AreaType::ServiceArea};
Area corridor{GeoPoint2DList{GeoPoint2D{47.767853, 16.530482},
GeoPoint2D{47.768004, 16.530382},
GeoPoint2D{47.768035, 16.530549},
GeoPoint2D{47.767880, 16.530629}},
10, /*altitude*/
1, /*layers*/
AreaType::Corridor};
Scenario scenario;
scenario.addArea(measurementArea);
scenario.addArea(serviceArea);
//scenario.addArea(corridor);
// Scenario defined?
double tileWidth = 5; // m
double tileHeight = 5; // m
double minTileArea = 2; // m^2
REQUIRE(scenario.defined(tileWidth, tileHeight, minTileArea) == false);
}
//===========================================================================================
// FlightPlan
//===========================================================================================
TEST_CASE( "Test FlightPlan Class. Visual." ) {
// Define Scenario.
Area measurementArea{GeoPoint2DList{GeoPoint2D{47.768120, 16.530380},
GeoPoint2D{47.768205, 16.530558},
GeoPoint2D{47.768147, 16.530566},
GeoPoint2D{47.768326, 16.530926},
GeoPoint2D{47.768135, 16.531025},
GeoPoint2D{47.768144, 16.530845},
GeoPoint2D{47.768103, 16.530978},
GeoPoint2D{47.767940, 16.530393}},
10, /*altitude*/
1, /*layers*/
AreaType::MeasurementArea};
Area serviceArea{GeoPoint2DList{GeoPoint2D{47.767874, 16.530409},
GeoPoint2D{47.767968, 16.530677},
GeoPoint2D{47.767860, 16.530723},
GeoPoint2D{47.767777, 16.530447}},
10, /*altitude*/
1, /*layers*/
AreaType::ServiceArea};
Area corridor{GeoPoint2DList{GeoPoint2D{47.767853, 16.530482},
GeoPoint2D{47.768004, 16.530382},
GeoPoint2D{47.768035, 16.530549},
GeoPoint2D{47.767880, 16.530629}},
10, /*altitude*/
1, /*layers*/
AreaType::Corridor};
Scenario scenario;
scenario.addArea(measurementArea);
scenario.addArea(serviceArea);
scenario.addArea(corridor);
// Parameters
double tileWidth = 5; // m
double tileHeight = 5; // m
double minTileArea = 5; // m^2
double lineDistance = 1; // m
double minTransectLength = 2; // m
REQUIRE(scenario.defined(tileWidth, tileHeight, minTileArea) == true);
// Generate pseudo progress.
size_t n = scenario.getTilesENU().size();
vector<int8_t> progress;
progress.reserve(n);
// Random Seed =======================================================================
//srand(time(NULL)); // init. random seed
for (size_t i=0; i < n; ++i){
int p = int(rand()/double(RAND_MAX)*200);
progress.push_back(p >= 100 ? 100 : p);
}
// Generate flightplan.
FlightPlan flightPlan;
flightPlan.setProgress(progress);
flightPlan.setScenario(scenario);
auto start = std::chrono::high_resolution_clock::now();
REQUIRE(flightPlan.generate(lineDistance, minTransectLength) == true);
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start);
cout << "Execution time flightPlan.generate(): ";
cout << delta.count();
cout << " ms" << endl;
// Store to svg.
std::ofstream svg("FlightPlan0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 400, 400);
const BoostPolygon &boost_measurement_area = scenario.getMeasurementAreaENU();
const BoostPolygon &boost_service_area = scenario.getServiceAreaENU();
const BoostPolygon &boost_corridor_area = scenario.getCorridorENU();
const BoostPolygon &boos_joined_area = scenario.getJoineAreaENU();
const BoostPolygon &boost_bbox = scenario.getMeasurementAreaBBoxENU().corners;
mapper.add(boost_measurement_area);
mapper.add(boost_service_area);
mapper.add(boost_corridor_area);
mapper.add(boos_joined_area);
mapper.add(boost_bbox);
mapper.map(boost_measurement_area, "fill-opacity:0.1;fill:rgb(0,255,0);stroke:rgb(0,255,0);stroke-width:2");
mapper.map(boost_service_area, "fill-opacity:0.1;fill:rgb(235, 232, 52);stroke:rgb(235, 232, 52);stroke-width:2");
mapper.map(boost_corridor_area, "fill-opacity:0.1;fill:rgb(52, 171, 235);stroke:rgb(52, 171, 235);stroke-width:2");
mapper.map(boos_joined_area, "fill-opacity:0.0;fill:rgb(245, 66, 218);stroke:rgb(245, 66, 218);stroke-width:3");
mapper.map(boost_bbox, "fill-opacity:0.0;fill:rgb(255, 55, 0);stroke:rgb(255, 55, 0);stroke-width:2");
auto tiles = scenario.getTilesENU();
//cout << "Tile count: " << tiles.size() << endl;
for (auto tile : tiles) {
mapper.add(tile);
mapper.map(tile, "fill-opacity:0.1;fill:rgb(0,0,0);stroke:rgb(0,0,0);stroke-width:2");
}
auto center_points = scenario.getTileCenterPointsENU();
for (size_t i=0; i < n; ++i) {
BoostPoint point{scenario.getTileCenterPointsENU()[i]};
mapper.add(point);
if (progress[i] < 50)
mapper.map(point, "fill-opacity:0.5;fill:rgb(255, 55, 0);stroke:rgb(255, 55, 0);stroke-width:2", 1);
else if (progress[i] < 100)
mapper.map(point, "fill-opacity:0.5;fill:rgb(245, 155, 66);stroke:rgb(245, 155, 66);stroke-width:2", 1);
else
mapper.map(point, "fill-opacity:0.5;fill:rgb(17, 255, 0);stroke:rgb(17, 255, 0);stroke-width:2", 1);
}
const vector<BoostLineString> &transects = flightPlan.getTransects();
for (auto t : transects){
mapper.add(t);
mapper.map(t, "fill-opacity:0.1;fill:rgb(255, 55, 0);stroke:rgb(255, 55, 0);stroke-width:6");
}
const BoostLineString &waypoints = flightPlan.getWaypointsENU();
cout << "Number of waypoints: " << waypoints.size() << endl;
mapper.add(waypoints);
mapper.map(waypoints, "fill-opacity:0.1;fill:rgb(170, 255, 0);stroke:rgb(170, 255, 0);stroke-width:2");
#ifndef NDEBUG
const BoostLineString &pathVertices = flightPlan.getPathVertices();
for (size_t i=0; i<pathVertices.size(); ++i){
mapper.text(pathVertices[i], to_string(i), ".small { font: italic 12px sans-serif; }");
}
#endif
// Waypoints inside joined Area?
BoostPolygon jAreaOffset;
offsetPolygon(scenario.getJoineAreaENU(), jAreaOffset, 0.1);
REQUIRE(bg::within(flightPlan.getWaypointsENU(), jAreaOffset));
}
#define CATCH_CONFIG_MAIN
#include "snake_geometry.h"
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include "catch.hpp"
using namespace snake_geometry;
using namespace std;
TEST_CASE( "Test toENU() and fromENU()", "[WGS84]" ) {
GeoPoint3D ref{48.230612, 16.297824, 0};
GeoPoint3D poi{48.231159, 16.298406, 2};
Point3D zero;
toENU(ref, ref, zero);
REQUIRE( zero[0] == Approx(0));
REQUIRE( zero[1] == Approx(0));
REQUIRE( zero[2] == Approx(0));
Point3D poiENU;
toENU(ref, poi, poiENU);
GeoPoint3D poi_same;
fromENU(ref, poiENU, poi_same);
Point3D diff;
toENU(poi_same, poi, diff);
REQUIRE( abs(diff[0]) <= 1e6);
REQUIRE( abs(diff[1]) <= 1e6);
REQUIRE( abs(diff[2]) <= 1e6);
}
TEST_CASE( "Test polygonCenter(), check out polygonCenter0.svg!" ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{100, 0});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPoint center;
polygonCenter(polygon, center);
// Write results to svg file.
std::ofstream svg("polygonCenter0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(center);
mapper.add(polygon);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(center, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5);
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(polygon) << endl;
//cout << boost::geometry::wkt<point_type>(center) << endl;
// Center inside polygon?
REQUIRE(boost::geometry::within(center, polygon) == true);
}
TEST_CASE( "Test polygonCenter(), check out polygonCenter1.svg!" ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{50, 0});
polygon.outer().push_back(BoostPoint{50, 50});
polygon.outer().push_back(BoostPoint{100, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPoint center;
polygonCenter(polygon, center);
// Write results to svg file.
std::ofstream svg("polygonCenter1.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(center);
mapper.add(polygon);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(center, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5);
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(polygon) << endl;
//cout << boost::geometry::wkt<point_type>(center) << endl;
// Center inside polygon?
REQUIRE(boost::geometry::within(center, polygon) == true);
}
TEST_CASE( "Test polygonCenter(), check out polygonCenter2.svg!" ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{20, 0});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{100, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPoint center;
polygonCenter(polygon, center);
// Convert to boost.
// Write results to svg file.
std::ofstream svg("polygonCenter2.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(center);
mapper.add(polygon);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(center, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5);
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(polygon) << endl;
//cout << boost::geometry::wkt<point_type>(center) << endl;
// Center inside polygon?
REQUIRE(boost::geometry::within(center, polygon) == true);
}
TEST_CASE( "Test polygonCenter(), check out polygonCenter3.svg!" ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPoint center;
polygonCenter(polygon, center);
// Write results to svg file.
std::ofstream svg("polygonCenter3.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(center);
mapper.add(polygon);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(center, "fill-opacity:0.5;fill:rgb(153,204,0);stroke:rgb(153,204,0);stroke-width:2", 5);
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(polygon) << endl;
//cout << boost::geometry::wkt<point_type>(center) << endl;
// Center inside polygon?
REQUIRE(boost::geometry::within(center, polygon) == true);
}
TEST_CASE( "Test minimalBoundingBox(), check out minimalBoundingBox0.svg!" ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
min_bbox_rt bbox;
minimalBoundingBox(polygon, bbox);
// Write results to svg file.
std::ofstream svg("minimalBoundingBox0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(bbox.corners);
mapper.add(polygon);
mapper.map(bbox.corners, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(polygon) << endl;
//cout << boost::geometry::wkt<polygon_type>(bbox.corners) << endl;
}
TEST_CASE( "Test minimalBoundingBox(), check out minimalBoundingBox1.svg! Rotated polygon." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
// Rotate polygon
boost::geometry::strategy::transform::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(45);
BoostPolygon rotated_polygon;
boost::geometry::transform(polygon, rotated_polygon, rotate);
min_bbox_rt bbox;
minimalBoundingBox(rotated_polygon, bbox);
// Write results to svg file.
std::ofstream svg("minimalBoundingBox1.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(bbox.corners);
mapper.add(rotated_polygon);
mapper.map(bbox.corners, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(rotated_polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(rotated_polygon) << endl;
//cout << boost::geometry::wkt<polygon_type>(bbox.corners) << endl;
}
TEST_CASE( "Test minimalBoundingBox(), check out minimalBoundingBox2.svg! Non convex." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{30, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
// Rotate polygon
boost::geometry::strategy::transform::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(45);
BoostPolygon rotated_polygon;
boost::geometry::transform(polygon, rotated_polygon, rotate);
min_bbox_rt bbox;
minimalBoundingBox(rotated_polygon, bbox);
// Write results to svg file.
std::ofstream svg("minimalBoundingBox2.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(bbox.corners);
mapper.add(rotated_polygon);
mapper.map(bbox.corners, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(rotated_polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(rotated_polygon) << endl;
//cout << boost::geometry::wkt<polygon_type>(bbox.corners) << endl;
}
TEST_CASE( "Test minimalBoundingBox(), check out minimalBoundingBox3.svg! Rotated polygon." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{10, 70});
polygon.outer().push_back(BoostPoint{30, 50});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
// Rotate polygon
boost::geometry::strategy::transform::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(45);
BoostPolygon rotated_polygon;
boost::geometry::transform(polygon, rotated_polygon, rotate);
min_bbox_rt bbox;
minimalBoundingBox(rotated_polygon, bbox);
// Write results to svg file.
std::ofstream svg("minimalBoundingBox3.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(bbox.corners);
mapper.add(rotated_polygon);
mapper.map(bbox.corners, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(rotated_polygon, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
// Print to standard output.
//cout << boost::geometry::wkt<polygon_type>(rotated_polygon) << endl;
//cout << boost::geometry::wkt<polygon_type>(bbox.corners) << endl;
}
TEST_CASE( "Various tests with empty polygons" ) {
BoostPolygon empty_polygon;
min_bbox_rt bbox;
minimalBoundingBox(empty_polygon, bbox);
BoostPoint center;
polygonCenter(empty_polygon, center);
}
TEST_CASE( "Test isClockwise()" ) {
Point2DList list1{Point2D{0,0},
Point2D{0,1},
Point2D{1,1}};
REQUIRE(isClockwise(list1) == true);
Point2DList list2{Point2D{0,0},
Point2D{1,1},
Point2D{0,1}};
REQUIRE(isClockwise(list2) == false);
}
TEST_CASE( "Test offsetPolygon(), positive." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{30, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 10);
// Write results to svg file.
std::ofstream svg("offsetPolygon0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygon);
mapper.add(polygonOffset);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
REQUIRE(bg::within(polygon, polygonOffset) == true);
}
TEST_CASE( "Test offsetPolygon(), negative." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{30, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, -10);
// Write results to svg file.
std::ofstream svg("offsetPolygon1.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygon);
mapper.add(polygonOffset);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
REQUIRE(bg::within(polygonOffset, polygon) == true);
}
TEST_CASE( "Test offsetPolygon(), positive, huge (miter test)." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{70, 0});
polygon.outer().push_back(BoostPoint{30, 50});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{0, 40});
polygon.outer().push_back(BoostPoint{0, 0});
bg::correct(polygon);
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 100);
// Write results to svg file.
std::ofstream svg("offsetPolygon2.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygon);
mapper.add(polygonOffset);
mapper.map(polygon, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
REQUIRE(bg::within(polygon, polygonOffset) == true);
}
TEST_CASE( "Test dijkstraAlgorithm() 1." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{100, 0});
polygon.outer().push_back(BoostPoint{80, 0});
polygon.outer().push_back(BoostPoint{50, 30});
polygon.outer().push_back(BoostPoint{20, 0});
polygon.outer().push_back(BoostPoint{0, 0});
BoostPoint startVertex{10, 10};
BoostPoint endVertex{90, 10};
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 0.1);
BoostLineString vertices;
vertices.push_back(startVertex);
vertices.push_back(endVertex);
for (size_t i=0; i < polygon.outer().size()-1; ++i)
vertices.push_back(polygon.outer()[i]);
size_t n = vertices.size();
Matrix<double> graph(n, n);
graphFromPolygon(polygonOffset, vertices, graph);
// cout << "graph:" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << graph[i][j] << " ";
// }
// cout << endl;
// }
std::vector<size_t> pathIndices;
auto distance = [graph](size_t i, size_t j){ return graph.get(i, j); };
// cout << "distance():" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << distance(i, j) << " ";
// }
// cout << endl;
// }
REQUIRE(dijkstraAlgorithm(n, 0, 1, pathIndices, distance));
BoostLineString path;
for (auto idx : pathIndices)
path.push_back(vertices[idx]);
REQUIRE(bg::within(path, polygonOffset));
// Write results to svg file.
std::ofstream svg("dijkstraAlgorithm0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygonOffset);
mapper.add(path);
mapper.add(startVertex);
mapper.add(endVertex);
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(path, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(startVertex, "fill-opacity:0.5;fill:rgb(250, 231, 25);stroke:rgb(250, 231, 25);stroke-width:2", 2);
mapper.map(endVertex, "fill-opacity:0.5;fill:rgb(25, 250, 243);stroke:rgb(25, 250, 243);stroke-width:2", 2);
}
TEST_CASE( "Test dijkstraAlgorithm() 2, more complex Polygon." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{100, 0});
polygon.outer().push_back(BoostPoint{80, 0});
polygon.outer().push_back(BoostPoint{80, 30});
polygon.outer().push_back(BoostPoint{95, 30});
polygon.outer().push_back(BoostPoint{95, 80});
polygon.outer().push_back(BoostPoint{20, 80});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{40, 50});
polygon.outer().push_back(BoostPoint{40, 30});
polygon.outer().push_back(BoostPoint{40, 0});
polygon.outer().push_back(BoostPoint{0, 0});
BoostPoint startVertex{10, 10};
BoostPoint endVertex{90, 10};
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 0.1);
BoostLineString vertices;
vertices.push_back(startVertex);
vertices.push_back(endVertex);
for (size_t i=0; i < polygon.outer().size()-1; ++i)
vertices.push_back(polygon.outer()[i]);
size_t n = vertices.size();
Matrix<double> graph(n, n);
graphFromPolygon(polygonOffset, vertices, graph);
// cout << "graph:" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << graph[i][j] << " ";
// }
// cout << endl;
// }
std::vector<size_t> pathIndices;
auto distance = [graph](size_t i, size_t j){ return graph.get(i, j); };
// cout << "distance():" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << distance(i, j) << " ";
// }
// cout << endl;
// }
REQUIRE(dijkstraAlgorithm(n, 0, 1, pathIndices, distance));
BoostLineString path;
for (auto idx : pathIndices)
path.push_back(vertices[idx]);
REQUIRE(bg::within(path, polygonOffset));
// Write results to svg file.
std::ofstream svg("dijkstraAlgorithm1.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygonOffset);
mapper.add(path);
mapper.add(startVertex);
mapper.add(endVertex);
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(path, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(startVertex, "fill-opacity:0.5;fill:rgb(250, 231, 25);stroke:rgb(250, 231, 25);stroke-width:2", 2);
mapper.map(endVertex, "fill-opacity:0.5;fill:rgb(25, 250, 243);stroke:rgb(25, 250, 243);stroke-width:2", 2);
}
TEST_CASE( "Test dijkstraAlgorithm() 3, performance Test." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{100, 0});
polygon.outer().push_back(BoostPoint{80, 0});
polygon.outer().push_back(BoostPoint{80, 30});
polygon.outer().push_back(BoostPoint{95, 30});
polygon.outer().push_back(BoostPoint{95, 80});
polygon.outer().push_back(BoostPoint{20, 80});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{40, 50});
polygon.outer().push_back(BoostPoint{40, 30});
polygon.outer().push_back(BoostPoint{40, 0});
polygon.outer().push_back(BoostPoint{0, 0});
BoostPoint startVertex{10, 10};
BoostPoint endVertex{90, 10};
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 0.1);
BoostLineString vertices;
vertices.push_back(startVertex);
vertices.push_back(endVertex);
for (size_t i=0; i < polygon.outer().size()-1; ++i)
vertices.push_back(polygon.outer()[i]);
// add extra load...
size_t n = 100;
size_t lim = n-vertices.size();
BoostPoint v{10,90};
for (size_t i=0; i < lim; ++i)
vertices.push_back(v);
Matrix<double> graph(n, n);
auto start = std::chrono::high_resolution_clock::now();
graphFromPolygon(polygonOffset, vertices, graph);
cout << "Execution time graphFromPolygon() n = " << n << ": ";
cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start).count();
cout << " ms" << endl;
// cout << "graph:" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << graph[i][j] << " ";
// }
// cout << endl;
// }
std::vector<size_t> pathIndices;
auto distance = [graph](size_t i, size_t j){ return graph.get(i, j); };
// cout << "distance():" << endl;
// for (size_t i=0; i<n; ++i){
// for (size_t j=0; j<n; ++j){
// cout << distance(i, j) << " ";
// }
// cout << endl;
// }
start = std::chrono::high_resolution_clock::now();
REQUIRE(dijkstraAlgorithm(n, 0, 1, pathIndices, distance));
cout << "Execution time dijkstraAlgorithm() n = " << n << ": ";
cout << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start).count();
cout << " ms" << endl;
BoostLineString path;
for (auto idx : pathIndices)
path.push_back(vertices[idx]);
REQUIRE(bg::within(path, polygonOffset));
// Write results to svg file.
std::ofstream svg("dijkstraAlgorithm2.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygonOffset);
mapper.add(path);
mapper.add(startVertex);
mapper.add(endVertex);
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(path, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(startVertex, "fill-opacity:0.5;fill:rgb(250, 231, 25);stroke:rgb(250, 231, 25);stroke-width:2", 2);
mapper.map(endVertex, "fill-opacity:0.5;fill:rgb(25, 250, 243);stroke:rgb(25, 250, 243);stroke-width:2", 2);
}
TEST_CASE( "Test shortestPathFromGraph() 1." ) {
BoostPolygon polygon;
polygon.outer().push_back(BoostPoint{0, 0});
polygon.outer().push_back(BoostPoint{0, 100});
polygon.outer().push_back(BoostPoint{100, 100});
polygon.outer().push_back(BoostPoint{100, 0});
polygon.outer().push_back(BoostPoint{80, 0});
polygon.outer().push_back(BoostPoint{80, 30});
polygon.outer().push_back(BoostPoint{95, 30});
polygon.outer().push_back(BoostPoint{95, 80});
polygon.outer().push_back(BoostPoint{20, 80});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{20, 50});
polygon.outer().push_back(BoostPoint{40, 50});
polygon.outer().push_back(BoostPoint{40, 30});
polygon.outer().push_back(BoostPoint{40, 0});
polygon.outer().push_back(BoostPoint{0, 0});
BoostPoint startVertex{10, 10};
BoostPoint endVertex{90, 10};
BoostPolygon polygonOffset;
offsetPolygon(polygon, polygonOffset, 0.2);
BoostLineString vertices;
vertices.push_back(startVertex);
vertices.push_back(endVertex);
for (size_t i=0; i < polygon.outer().size()-1; ++i)
vertices.push_back(polygon.outer()[i]);
size_t n = vertices.size();
Matrix<double> graph(n, n);
graphFromPolygon(polygonOffset, vertices, graph);
std::vector<size_t> pathIndices;
shortestPathFromGraph(graph, 0, 1, pathIndices);
BoostLineString path;
for (auto idx : pathIndices)
path.push_back(vertices[idx]);
// Write results to svg file.
std::ofstream svg("shortestPathFromGraph0.svg");
boost::geometry::svg_mapper<BoostPoint> mapper(svg, 200, 200);
mapper.add(polygonOffset);
mapper.add(path);
mapper.add(startVertex);
mapper.add(endVertex);
mapper.map(polygonOffset, "fill-opacity:0.1;fill:rgb(51,51,153);stroke:rgb(51,51,153);stroke-width:2");
mapper.map(path, "fill-opacity:0.1;fill:rgb(255,0,0);stroke:rgb(255,0,0);stroke-width:2");
mapper.map(startVertex, "fill-opacity:0.5;fill:rgb(250, 231, 25);stroke:rgb(250, 231, 25);stroke-width:2", 2);
mapper.map(endVertex, "fill-opacity:0.5;fill:rgb(25, 250, 243);stroke:rgb(25, 250, 243);stroke-width:2", 2);
REQUIRE(bg::within(path, polygonOffset));
}
......@@ -209,7 +209,7 @@ LinuxBuild {
CONFIG += qt \
thread \
c++11
c++14
DebugBuild {
CONFIG -= qtquickcompiler
......@@ -360,6 +360,7 @@ INCLUDEPATH += \
src/QtLocationPlugin \
src/QtLocationPlugin/QMLControl \
src/Settings \
src/Snake \
src/Terrain \
src/VehicleSetup \
src/ViewWidgets \
......@@ -402,6 +403,31 @@ FORMS += \
#
HEADERS += \
src/Snake/clipper/clipper.hpp \
src/Snake/mapbox/feature.hpp \
src/Snake/mapbox/geometry.hpp \
src/Snake/mapbox/geometry/box.hpp \
src/Snake/mapbox/geometry/empty.hpp \
src/Snake/mapbox/geometry/envelope.hpp \
src/Snake/mapbox/geometry/for_each_point.hpp \
src/Snake/mapbox/geometry/geometry.hpp \
src/Snake/mapbox/geometry/line_string.hpp \
src/Snake/mapbox/geometry/multi_line_string.hpp \
src/Snake/mapbox/geometry/multi_point.hpp \
src/Snake/mapbox/geometry/multi_polygon.hpp \
src/Snake/mapbox/geometry/point.hpp \
src/Snake/mapbox/geometry/point_arithmetic.hpp \
src/Snake/mapbox/geometry/polygon.hpp \
src/Snake/mapbox/geometry_io.hpp \
src/Snake/mapbox/optional.hpp \
src/Snake/mapbox/polylabel.hpp \
src/Snake/mapbox/recursive_wrapper.hpp \
src/Snake/mapbox/variant.hpp \
src/Snake/mapbox/variant_io.hpp \
src/Snake/snake.h \
src/Snake/snake_geometry.h \
src/Snake/snake_global.h \
src/Wima/WimaControllerDetail.h \
src/api/QGCCorePlugin.h \
src/api/QGCOptions.h \
src/api/QGCSettings.h \
......@@ -435,8 +461,13 @@ HEADERS += \
src/Wima/TestPolygonCalculus.h \
src/Wima/testplanimetrycalculus.h \
src/Settings/WimaSettings.h \
src/QmlControls/QmlObjectVectorModel.h
src/QmlControls/QmlObjectVectorModel.h \
src/comm/utilities.h
SOURCES += \
src/Snake/clipper/clipper.cpp \
src/Snake/snake.cpp \
src/Snake/snake_geometry.cpp \
src/Wima/WimaControllerDetail.cc \
src/api/QGCCorePlugin.cc \
src/api/QGCOptions.cc \
src/api/QGCSettings.cc \
......
// This file is autogenerated. Changes will be overwritten.
#include "G2HJQHALR5/moc_AirspaceManager.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_GeoTagController.cpp"
#include "EWIEGA46WW/moc_LogDownloadController.cpp"
#include "EWIEGA46WW/moc_LogDownloadTest.cpp"
#include "EWIEGA46WW/moc_MavlinkConsoleController.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_AudioOutput.cpp"
#include "EWIEGA46WW/moc_AudioOutputTest.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "FFHNZN56LN/moc_APMAirframeComponent.cpp"
#include "FFHNZN56LN/moc_APMAirframeComponentController.cpp"
#include "FFHNZN56LN/moc_APMAirframeLoader.cpp"
#include "FFHNZN56LN/moc_APMAutoPilotPlugin.cpp"
#include "FFHNZN56LN/moc_APMCameraComponent.cpp"
#include "FFHNZN56LN/moc_APMCompassCal.cpp"
#include "FFHNZN56LN/moc_APMFlightModesComponent.cpp"
#include "FFHNZN56LN/moc_APMFlightModesComponentController.cpp"
#include "FFHNZN56LN/moc_APMHeliComponent.cpp"
#include "FFHNZN56LN/moc_APMLightsComponent.cpp"
#include "FFHNZN56LN/moc_APMMotorComponent.cpp"
#include "FFHNZN56LN/moc_APMPowerComponent.cpp"
#include "FFHNZN56LN/moc_APMRadioComponent.cpp"
#include "FFHNZN56LN/moc_APMSafetyComponent.cpp"
#include "FFHNZN56LN/moc_APMSensorsComponent.cpp"
#include "FFHNZN56LN/moc_APMSensorsComponentController.cpp"
#include "FFHNZN56LN/moc_APMSubFrameComponent.cpp"
#include "FFHNZN56LN/moc_APMTuningComponent.cpp"
#include "EWIEGA46WW/moc_AutoPilotPlugin.cpp"
#include "U2NUAE3D6E/moc_ESP8266Component.cpp"
#include "U2NUAE3D6E/moc_ESP8266ComponentController.cpp"
#include "U2NUAE3D6E/moc_MotorComponent.cpp"
#include "U2NUAE3D6E/moc_RadioComponentController.cpp"
#include "U2NUAE3D6E/moc_SyslinkComponent.cpp"
#include "U2NUAE3D6E/moc_SyslinkComponentController.cpp"
#include "KYKGY3RYO2/moc_GenericAutoPilotPlugin.cpp"
#include "KIEVYJJCTC/moc_AirframeComponent.cpp"
#include "KIEVYJJCTC/moc_AirframeComponentController.cpp"
#include "KIEVYJJCTC/moc_CameraComponent.cpp"
#include "KIEVYJJCTC/moc_FlightModesComponent.cpp"
#include "KIEVYJJCTC/moc_PX4AdvancedFlightModesController.cpp"
#include "KIEVYJJCTC/moc_PX4AirframeLoader.cpp"
#include "KIEVYJJCTC/moc_PX4AutoPilotPlugin.cpp"
#include "KIEVYJJCTC/moc_PX4RadioComponent.cpp"
#include "KIEVYJJCTC/moc_PX4SimpleFlightModesController.cpp"
#include "KIEVYJJCTC/moc_PX4TuningComponent.cpp"
#include "KIEVYJJCTC/moc_PowerComponent.cpp"
#include "KIEVYJJCTC/moc_PowerComponentController.cpp"
#include "KIEVYJJCTC/moc_SafetyComponent.cpp"
#include "KIEVYJJCTC/moc_SensorsComponent.cpp"
#include "KIEVYJJCTC/moc_SensorsComponentController.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_QGCCameraControl.cpp"
#include "EWIEGA46WW/moc_QGCCameraManager.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_Fact.cpp"
#include "L2ABTUHX6Y/moc_FactPanelController.cpp"
#include "EWIEGA46WW/moc_FactGroup.cpp"
#include "EWIEGA46WW/moc_FactMetaData.cpp"
#include "EWIEGA46WW/moc_FactSystem.cpp"
#include "EWIEGA46WW/moc_FactSystemTestBase.cpp"
#include "EWIEGA46WW/moc_FactSystemTestGeneric.cpp"
#include "EWIEGA46WW/moc_FactSystemTestPX4.cpp"
#include "EWIEGA46WW/moc_FactValueSliderListModel.cpp"
#include "EWIEGA46WW/moc_ParameterManager.cpp"
#include "EWIEGA46WW/moc_ParameterManagerTest.cpp"
#include "EWIEGA46WW/moc_SettingsFact.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "FFHNZN56LN/moc_APMFirmwarePlugin.cpp"
#include "FFHNZN56LN/moc_APMFirmwarePluginFactory.cpp"
#include "FFHNZN56LN/moc_APMParameterMetaData.cpp"
#include "FFHNZN56LN/moc_ArduCopterFirmwarePlugin.cpp"
#include "FFHNZN56LN/moc_ArduPlaneFirmwarePlugin.cpp"
#include "FFHNZN56LN/moc_ArduRoverFirmwarePlugin.cpp"
#include "FFHNZN56LN/moc_ArduSubFirmwarePlugin.cpp"
#include "EWIEGA46WW/moc_CameraMetaData.cpp"
#include "EWIEGA46WW/moc_FirmwarePlugin.cpp"
#include "EWIEGA46WW/moc_FirmwarePluginManager.cpp"
#include "KIEVYJJCTC/moc_PX4FirmwarePlugin.cpp"
#include "KIEVYJJCTC/moc_PX4FirmwarePluginFactory.cpp"
#include "KIEVYJJCTC/moc_PX4ParameterMetaData.cpp"
......@@ -156,6 +156,36 @@ Item {
id: mainColumn
spacing: ScreenTools.defaultFontPixelHeight * 0.3
SectionHeader{
id: snakeHeader
text: qsTr("Snake Settings")
}
GridLayout {
columns: 2
rowSpacing: ScreenTools.defaultFontPixelHeight * 0.5
columnSpacing: ScreenTools.defaultFontPixelHeight * 0.5
visible: snakeHeader.checked
FactCheckBox {
text: wimaController.enableSnake.value ? qsTr("Disable Snake") : qsTr("Enable Snake")
fact: wimaController.enableSnake
Layout.fillWidth: true
}
QGCLabel {
text: wimaController.snakeConnectionStatus.value === 1 ? qsTr("Connected") : qsTr("Not Connected")
Layout.fillWidth: true
}
QGCLabel {
text: wimaController.snakeCalcInProgress.value === true ? qsTr("Calculation: In Progress") : qsTr("Calculation: Idle")
Layout.fillWidth: true
Layout.columnSpan: 2
}
}
SectionHeader{
id: missionHeader
text: qsTr("Phase Settings")
......
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_VideoManager.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "WHF3XMZT5M/moc_ValuesWidgetController.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_FollowMe.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_GPSManager.cpp"
#include "EWIEGA46WW/moc_GPSProvider.cpp"
#include "I3QYLTSP63/moc_RTCMMavlink.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_Joystick.cpp"
#include "EWIEGA46WW/moc_JoystickManager.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_CameraCalc.cpp"
#include "EWIEGA46WW/moc_CameraCalcTest.cpp"
#include "EWIEGA46WW/moc_CameraSection.cpp"
#include "EWIEGA46WW/moc_CameraSectionTest.cpp"
#include "EWIEGA46WW/moc_CameraSpec.cpp"
#include "EWIEGA46WW/moc_ComplexMissionItem.cpp"
#include "EWIEGA46WW/moc_CorridorScanComplexItem.cpp"
#include "EWIEGA46WW/moc_CorridorScanComplexItemTest.cpp"
#include "EWIEGA46WW/moc_FixedWingLandingComplexItem.cpp"
#include "EWIEGA46WW/moc_GeoFenceController.cpp"
#include "EWIEGA46WW/moc_GeoFenceManager.cpp"
#include "EWIEGA46WW/moc_MissionCommandList.cpp"
#include "EWIEGA46WW/moc_MissionCommandTree.cpp"
#include "EWIEGA46WW/moc_MissionCommandTreeTest.cpp"
#include "EWIEGA46WW/moc_MissionCommandUIInfo.cpp"
#include "EWIEGA46WW/moc_MissionController.cpp"
#include "EWIEGA46WW/moc_MissionControllerManagerTest.cpp"
#include "EWIEGA46WW/moc_MissionControllerTest.cpp"
#include "EWIEGA46WW/moc_MissionItem.cpp"
#include "EWIEGA46WW/moc_MissionItemTest.cpp"
#include "EWIEGA46WW/moc_MissionManager.cpp"
#include "EWIEGA46WW/moc_MissionManagerTest.cpp"
#include "EWIEGA46WW/moc_MissionSettingsItem.cpp"
#include "EWIEGA46WW/moc_MissionSettingsTest.cpp"
#include "EWIEGA46WW/moc_PlanElementController.cpp"
#include "EWIEGA46WW/moc_PlanManager.cpp"
#include "EWIEGA46WW/moc_PlanMasterController.cpp"
#include "EWIEGA46WW/moc_PlanMasterControllerTest.cpp"
#include "EWIEGA46WW/moc_QGCFenceCircle.cpp"
#include "EWIEGA46WW/moc_QGCFencePolygon.cpp"
#include "EWIEGA46WW/moc_QGCMapCircle.cpp"
#include "EWIEGA46WW/moc_QGCMapPolygon.cpp"
#include "EWIEGA46WW/moc_QGCMapPolygonTest.cpp"
#include "EWIEGA46WW/moc_QGCMapPolyline.cpp"
#include "EWIEGA46WW/moc_QGCMapPolylineTest.cpp"
#include "EWIEGA46WW/moc_RallyPoint.cpp"
#include "EWIEGA46WW/moc_RallyPointController.cpp"
#include "EWIEGA46WW/moc_RallyPointManager.cpp"
#include "EWIEGA46WW/moc_Section.cpp"
#include "EWIEGA46WW/moc_SectionTest.cpp"
#include "EWIEGA46WW/moc_SimpleMissionItem.cpp"
#include "EWIEGA46WW/moc_SimpleMissionItemTest.cpp"
#include "EWIEGA46WW/moc_SpeedSection.cpp"
#include "EWIEGA46WW/moc_SpeedSectionTest.cpp"
#include "EWIEGA46WW/moc_StructureScanComplexItem.cpp"
#include "EWIEGA46WW/moc_StructureScanComplexItemTest.cpp"
#include "EWIEGA46WW/moc_SurveyComplexItem.cpp"
#include "EWIEGA46WW/moc_SurveyComplexItemTest.cpp"
#include "EWIEGA46WW/moc_TransectStyleComplexItem.cpp"
#include "EWIEGA46WW/moc_TransectStyleComplexItemTest.cpp"
#include "EWIEGA46WW/moc_VisualMissionItem.cpp"
#include "EWIEGA46WW/moc_VisualMissionItemTest.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_PositionManager.cpp"
#include "EWIEGA46WW/moc_SimulatedPosition.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_AppMessages.cpp"
#include "EWIEGA46WW/moc_CoordinateVector.cpp"
#include "EWIEGA46WW/moc_EditPositionDialogController.cpp"
#include "EWIEGA46WW/moc_ParameterEditorController.cpp"
#include "EWIEGA46WW/moc_QGCFileDialogController.cpp"
#include "EWIEGA46WW/moc_QGCGeoBoundingCube.cpp"
#include "EWIEGA46WW/moc_QGroundControlQmlGlobal.cpp"
#include "EWIEGA46WW/moc_QmlObjectListModel.cpp"
#include "EWIEGA46WW/moc_QmlTestWidget.cpp"
#include "EWIEGA46WW/moc_RCChannelMonitorController.cpp"
#include "EWIEGA46WW/moc_ScreenToolsController.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_QGCMapEngine.cpp"
#include "EWIEGA46WW/moc_QGCMapEngineData.cpp"
#include "EWIEGA46WW/moc_QGCMapTileSet.cpp"
#include "EWIEGA46WW/moc_QGCMapUrlEngine.cpp"
#include "EWIEGA46WW/moc_QGCTileCacheWorker.cpp"
#include "EWIEGA46WW/moc_QGeoCodeReplyQGC.cpp"
#include "EWIEGA46WW/moc_QGeoCodingManagerEngineQGC.cpp"
#include "EWIEGA46WW/moc_QGeoMapReplyQGC.cpp"
#include "EWIEGA46WW/moc_QGeoServiceProviderPluginQGC.cpp"
#include "EWIEGA46WW/moc_QGeoTileFetcherQGC.cpp"
#include "EWIEGA46WW/moc_QGeoTiledMappingManagerEngineQGC.cpp"
#include "QBQLKL2OAS/moc_QGCMapEngineManager.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_APMMavlinkStreamRateSettings.cpp"
#include "EWIEGA46WW/moc_AppSettings.cpp"
#include "EWIEGA46WW/moc_AutoConnectSettings.cpp"
#include "EWIEGA46WW/moc_BrandImageSettings.cpp"
#include "EWIEGA46WW/moc_FlightMapSettings.cpp"
#include "EWIEGA46WW/moc_FlyViewSettings.cpp"
#include "EWIEGA46WW/moc_PlanViewSettings.cpp"
#include "EWIEGA46WW/moc_RTKSettings.cpp"
#include "EWIEGA46WW/moc_SettingsGroup.cpp"
#include "EWIEGA46WW/moc_SettingsManager.cpp"
#include "EWIEGA46WW/moc_UnitsSettings.cpp"
#include "EWIEGA46WW/moc_VideoSettings.cpp"
#include "EWIEGA46WW/moc_WimaSettings.cpp"
This source diff could not be displayed because it is too large. You can view the blob instead.
/*******************************************************************************
* *
* 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 <vector>
#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
#include <queue>
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<LocalMinimum> 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<cInt> 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<cInt> 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<DoublePoint> 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
#pragma once
#include <mapbox/geometry.hpp>
#include <mapbox/variant.hpp>
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
namespace mapbox {
namespace feature {
struct value;
struct null_value_t
{
};
constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
constexpr bool operator<(const null_value_t&, const null_value_t&) { return false; }
constexpr null_value_t null_value = null_value_t();
// Multiple numeric types (uint64_t, int64_t, double) are present in order to support
// the widest possible range of JSON numbers, which do not have a maximum range.
// Implementations that produce `value`s should use that order for type preference,
// using uint64_t for positive integers, int64_t for negative integers, and double
// for non-integers and integers outside the range of 64 bits.
using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
mapbox::util::recursive_wrapper<std::vector<value>>,
mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
struct value : value_base
{
using value_base::value_base;
};
using property_map = std::unordered_map<std::string, value>;
// The same considerations and requirement for numeric types apply as for `value_base`.
using identifier = mapbox::util::variant<null_value_t, uint64_t, int64_t, double, std::string>;
template <class T>
struct feature
{
using coordinate_type = T;
using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
geometry_type geometry;
property_map properties;
identifier id;
feature()
: geometry(),
properties(),
id() {}
feature(geometry_type const& geom_)
: geometry(geom_),
properties(),
id() {}
feature(geometry_type&& geom_)
: geometry(std::move(geom_)),
properties(),
id() {}
feature(geometry_type const& geom_, property_map const& prop_)
: geometry(geom_), properties(prop_), id() {}
feature(geometry_type&& geom_, property_map&& prop_)
: geometry(std::move(geom_)),
properties(std::move(prop_)),
id() {}
feature(geometry_type const& geom_, property_map const& prop_, identifier const& id_)
: geometry(geom_),
properties(prop_),
id(id_) {}
feature(geometry_type&& geom_, property_map&& prop_, identifier&& id_)
: geometry(std::move(geom_)),
properties(std::move(prop_)),
id(std::move(id_)) {}
};
template <class T>
constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
{
return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
}
template <class T>
constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
{
return !(lhs == rhs);
}
template <class T, template <typename...> class Cont = std::vector>
struct feature_collection : Cont<feature<T>>
{
using coordinate_type = T;
using feature_type = feature<T>;
using container_type = Cont<feature_type>;
using size_type = typename container_type::size_type;
template <class... Args>
feature_collection(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
feature_collection(std::initializer_list<feature_type> args)
: container_type(std::move(args)) {}
};
} // namespace feature
} // namespace mapbox
#pragma once
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/line_string.hpp>
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/multi_point.hpp>
#include <mapbox/geometry/multi_line_string.hpp>
#include <mapbox/geometry/multi_polygon.hpp>
#include <mapbox/geometry/geometry.hpp>
#include <mapbox/geometry/point_arithmetic.hpp>
#include <mapbox/geometry/for_each_point.hpp>
#include <mapbox/geometry/envelope.hpp>
#pragma once
#include <mapbox/geometry/point.hpp>
namespace mapbox {
namespace geometry {
template <typename T>
struct box
{
using coordinate_type = T;
using point_type = point<coordinate_type>;
constexpr box(point_type const& min_, point_type const& max_)
: min(min_), max(max_)
{
}
point_type min;
point_type max;
};
template <typename T>
constexpr bool operator==(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min == rhs.min && lhs.max == rhs.max;
}
template <typename T>
constexpr bool operator!=(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min != rhs.min || lhs.max != rhs.max;
}
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
struct empty
{
}; // this Geometry type represents the empty point set, ∅, for the coordinate space (OGC Simple Features).
constexpr bool operator==(empty, empty) { return true; }
constexpr bool operator!=(empty, empty) { return false; }
constexpr bool operator<(empty, empty) { return false; }
constexpr bool operator>(empty, empty) { return false; }
constexpr bool operator<=(empty, empty) { return true; }
constexpr bool operator>=(empty, empty) { return true; }
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/box.hpp>
#include <mapbox/geometry/for_each_point.hpp>
#include <limits>
namespace mapbox {
namespace geometry {
template <typename G, typename T = typename G::coordinate_type>
box<T> envelope(G const& geometry)
{
using limits = std::numeric_limits<T>;
T min_t = limits::has_infinity ? -limits::infinity() : limits::min();
T max_t = limits::has_infinity ? limits::infinity() : limits::max();
point<T> min(max_t, max_t);
point<T> max(min_t, min_t);
for_each_point(geometry, [&](point<T> const& point) {
if (min.x > point.x) min.x = point.x;
if (min.y > point.y) min.y = point.y;
if (max.x < point.x) max.x = point.x;
if (max.y < point.y) max.y = point.y;
});
return box<T>(min, max);
}
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/geometry.hpp>
namespace mapbox {
namespace geometry {
template <typename F>
void for_each_point(mapbox::geometry::empty const&, F&&)
{
}
template <typename Point, typename F>
auto for_each_point(Point&& point, F&& f)
-> decltype(point.x, point.y, void())
{
f(std::forward<Point>(point));
}
template <typename Container, typename F>
auto for_each_point(Container&& container, F&& f)
-> decltype(container.begin(), container.end(), void());
template <typename... Types, typename F>
void for_each_point(mapbox::util::variant<Types...> const& geom, F&& f)
{
mapbox::util::variant<Types...>::visit(geom, [&](auto const& g) {
for_each_point(g, f);
});
}
template <typename... Types, typename F>
void for_each_point(mapbox::util::variant<Types...>& geom, F&& f)
{
mapbox::util::variant<Types...>::visit(geom, [&](auto& g) {
for_each_point(g, f);
});
}
template <typename Container, typename F>
auto for_each_point(Container&& container, F&& f)
-> decltype(container.begin(), container.end(), void())
{
for (auto& e : container)
{
for_each_point(e, f);
}
}
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/empty.hpp>
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/line_string.hpp>
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/multi_point.hpp>
#include <mapbox/geometry/multi_line_string.hpp>
#include <mapbox/geometry/multi_polygon.hpp>
#include <mapbox/variant.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct geometry_collection;
template <typename T, template <typename...> class Cont = std::vector>
using geometry_base = mapbox::util::variant<empty,
point<T>,
line_string<T, Cont>,
polygon<T, Cont>,
multi_point<T, Cont>,
multi_line_string<T, Cont>,
multi_polygon<T, Cont>,
geometry_collection<T, Cont>>;
template <typename T, template <typename...> class Cont = std::vector>
struct geometry : geometry_base<T, Cont>
{
using coordinate_type = T;
using geometry_base<T>::geometry_base;
};
template <typename T, template <typename...> class Cont>
struct geometry_collection : Cont<geometry<T>>
{
using coordinate_type = T;
using geometry_type = geometry<T>;
using container_type = Cont<geometry_type>;
using size_type = typename container_type::size_type;
template <class... Args>
geometry_collection(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
geometry_collection(std::initializer_list<geometry_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct line_string : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
line_string(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
line_string(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/line_string.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_line_string : Cont<line_string<T>>
{
using coordinate_type = T;
using line_string_type = line_string<T>;
using container_type = Cont<line_string_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_line_string(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_line_string(std::initializer_list<line_string_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_point : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_point(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_point(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/polygon.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct multi_polygon : Cont<polygon<T>>
{
using coordinate_type = T;
using polygon_type = polygon<T>;
using container_type = Cont<polygon_type>;
using size_type = typename container_type::size_type;
template <class... Args>
multi_polygon(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
multi_polygon(std::initializer_list<polygon_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
template <typename T>
struct point
{
using coordinate_type = T;
constexpr point()
: x(), y()
{
}
constexpr point(T x_, T y_)
: x(x_), y(y_)
{
}
T x;
T y;
};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
template <typename T>
constexpr bool operator==(point<T> const& lhs, point<T> const& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
#pragma GCC diagnostic pop
template <typename T>
constexpr bool operator!=(point<T> const& lhs, point<T> const& rhs)
{
return !(lhs == rhs);
}
} // namespace geometry
} // namespace mapbox
#pragma once
namespace mapbox {
namespace geometry {
template <typename T>
point<T> operator+(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x + rhs.x, lhs.y + rhs.y);
}
template <typename T>
point<T> operator+(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x + rhs, lhs.y + rhs);
}
template <typename T>
point<T> operator-(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x - rhs.x, lhs.y - rhs.y);
}
template <typename T>
point<T> operator-(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x - rhs, lhs.y - rhs);
}
template <typename T>
point<T> operator*(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x * rhs.x, lhs.y * rhs.y);
}
template <typename T>
point<T> operator*(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x * rhs, lhs.y * rhs);
}
template <typename T>
point<T> operator/(point<T> const& lhs, point<T> const& rhs)
{
return point<T>(lhs.x / rhs.x, lhs.y / rhs.y);
}
template <typename T>
point<T> operator/(point<T> const& lhs, T const& rhs)
{
return point<T>(lhs.x / rhs, lhs.y / rhs);
}
template <typename T>
point<T>& operator+=(point<T>& lhs, point<T> const& rhs)
{
lhs.x += rhs.x;
lhs.y += rhs.y;
return lhs;
}
template <typename T>
point<T>& operator+=(point<T>& lhs, T const& rhs)
{
lhs.x += rhs;
lhs.y += rhs;
return lhs;
}
template <typename T>
point<T>& operator-=(point<T>& lhs, point<T> const& rhs)
{
lhs.x -= rhs.x;
lhs.y -= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator-=(point<T>& lhs, T const& rhs)
{
lhs.x -= rhs;
lhs.y -= rhs;
return lhs;
}
template <typename T>
point<T>& operator*=(point<T>& lhs, point<T> const& rhs)
{
lhs.x *= rhs.x;
lhs.y *= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator*=(point<T>& lhs, T const& rhs)
{
lhs.x *= rhs;
lhs.y *= rhs;
return lhs;
}
template <typename T>
point<T>& operator/=(point<T>& lhs, point<T> const& rhs)
{
lhs.x /= rhs.x;
lhs.y /= rhs.y;
return lhs;
}
template <typename T>
point<T>& operator/=(point<T>& lhs, T const& rhs)
{
lhs.x /= rhs;
lhs.y /= rhs;
return lhs;
}
} // namespace geometry
} // namespace mapbox
#pragma once
// mapbox
#include <mapbox/geometry/point.hpp>
// stl
#include <vector>
namespace mapbox {
namespace geometry {
template <typename T, template <typename...> class Cont = std::vector>
struct linear_ring : Cont<point<T>>
{
using coordinate_type = T;
using point_type = point<T>;
using container_type = Cont<point_type>;
using size_type = typename container_type::size_type;
template <class... Args>
linear_ring(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
linear_ring(std::initializer_list<point_type> args)
: container_type(std::move(args)) {}
};
template <typename T, template <typename...> class Cont = std::vector>
struct polygon : Cont<linear_ring<T>>
{
using coordinate_type = T;
using linear_ring_type = linear_ring<T>;
using container_type = Cont<linear_ring_type>;
using size_type = typename container_type::size_type;
template <class... Args>
polygon(Args&&... args) : container_type(std::forward<Args>(args)...)
{
}
polygon(std::initializer_list<linear_ring_type> args)
: container_type(std::move(args)) {}
};
} // namespace geometry
} // namespace mapbox
#pragma once
#include <mapbox/geometry/empty.hpp>
#include <mapbox/feature.hpp>
#include <iostream>
#include <string>
namespace mapbox {
namespace geometry {
std::ostream& operator<<(std::ostream& os, const empty&)
{
return os << "[]";
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const point<T>& point)
{
return os << "[" << point.x << "," << point.y << "]";
}
template <typename T, template <class, class...> class C, class... Args>
std::ostream& operator<<(std::ostream& os, const C<T, Args...>& cont)
{
os << "[";
for (auto it = cont.cbegin();;)
{
os << *it;
if (++it == cont.cend())
{
break;
}
os << ",";
}
return os << "]";
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const line_string<T>& geom)
{
return os << static_cast<typename line_string<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const linear_ring<T>& geom)
{
return os << static_cast<typename linear_ring<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const polygon<T>& geom)
{
return os << static_cast<typename polygon<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_point<T>& geom)
{
return os << static_cast<typename multi_point<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_line_string<T>& geom)
{
return os << static_cast<typename multi_line_string<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const multi_polygon<T>& geom)
{
return os << static_cast<typename multi_polygon<T>::container_type>(geom);
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const geometry<T>& geom)
{
geometry<T>::visit(geom, [&](const auto& g) { os << g; });
return os;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const geometry_collection<T>& geom)
{
return os << static_cast<typename geometry_collection<T>::container_type>(geom);
}
} // namespace geometry
namespace feature {
std::ostream& operator<<(std::ostream& os, const null_value_t&)
{
return os << "[]";
}
} // namespace feature
} // namespace mapbox
#ifndef MAPBOX_UTIL_OPTIONAL_HPP
#define MAPBOX_UTIL_OPTIONAL_HPP
#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
#include <type_traits>
#include <utility>
#include "variant.hpp"
namespace mapbox {
namespace util {
template <typename T>
class optional
{
static_assert(!std::is_reference<T>::value, "optional doesn't support references");
struct none_type
{
};
variant<none_type, T> variant_;
public:
optional() = default;
optional(optional const& rhs)
{
if (this != &rhs)
{ // protect against invalid self-assignment
variant_ = rhs.variant_;
}
}
optional(T const& v) { variant_ = v; }
explicit operator bool() const noexcept { return variant_.template is<T>(); }
T const& get() const { return variant_.template get<T>(); }
T& get() { return variant_.template get<T>(); }
T const& operator*() const { return this->get(); }
T operator*() { return this->get(); }
optional& operator=(T const& v)
{
variant_ = v;
return *this;
}
optional& operator=(optional const& rhs)
{
if (this != &rhs)
{
variant_ = rhs.variant_;
}
return *this;
}
template <typename... Args>
void emplace(Args&&... args)
{
variant_ = T{std::forward<Args>(args)...};
}
void reset() { variant_ = none_type{}; }
}; // class optional
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_OPTIONAL_HPP
#pragma once
#include <mapbox/geometry/polygon.hpp>
#include <mapbox/geometry/envelope.hpp>
#include <mapbox/geometry/point.hpp>
#include <mapbox/geometry/point_arithmetic.hpp>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
namespace mapbox {
namespace detail {
// get squared distance from a point to a segment
template <class T>
T getSegDistSq(const geometry::point<T>& p,
const geometry::point<T>& a,
const geometry::point<T>& b) {
auto x = a.x;
auto y = a.y;
auto dx = b.x - x;
auto dy = b.y - y;
if (dx != 0 || dy != 0) {
auto t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x = b.x;
y = b.y;
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}
dx = p.x - x;
dy = p.y - y;
return dx * dx + dy * dy;
}
// signed distance from point to polygon outline (negative if point is outside)
template <class T>
auto pointToPolygonDist(const geometry::point<T>& point, const geometry::polygon<T>& polygon) {
bool inside = false;
auto minDistSq = std::numeric_limits<double>::infinity();
for (const auto& ring : polygon) {
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const auto& a = ring[i];
const auto& b = ring[j];
if ((a.y > point.y) != (b.y > point.y) &&
(point.x < (b.x - a.x) * (point.y - a.y) / (b.y - a.y) + a.x)) inside = !inside;
minDistSq = std::min(minDistSq, getSegDistSq(point, a, b));
}
}
return (inside ? 1 : -1) * std::sqrt(minDistSq);
}
template <class T>
struct Cell {
Cell(const geometry::point<T>& c_, T h_, const geometry::polygon<T>& polygon)
: c(c_),
h(h_),
d(pointToPolygonDist(c, polygon)),
max(d + h * std::sqrt(2))
{}
geometry::point<T> c; // cell center
T h; // half the cell size
T d; // distance from cell center to polygon
T max; // max distance to polygon within a cell
};
// get polygon centroid
template <class T>
Cell<T> getCentroidCell(const geometry::polygon<T>& polygon) {
T area = 0;
geometry::point<T> c { 0, 0 };
const auto& ring = polygon.at(0);
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const geometry::point<T>& a = ring[i];
const geometry::point<T>& b = ring[j];
auto f = a.x * b.y - b.x * a.y;
c.x += (a.x + b.x) * f;
c.y += (a.y + b.y) * f;
area += f * 3;
}
return Cell<T>(area == 0 ? ring.at(0) : c / area, 0, polygon);
}
} // namespace detail
template <class T>
geometry::point<T> polylabel(const geometry::polygon<T>& polygon, T precision = 1, bool debug = false) {
using namespace detail;
// find the bounding box of the outer ring
const geometry::box<T> envelope = geometry::envelope(polygon.at(0));
const geometry::point<T> size {
envelope.max.x - envelope.min.x,
envelope.max.y - envelope.min.y
};
const T cellSize = std::min(size.x, size.y);
T h = cellSize / 2;
// a priority queue of cells in order of their "potential" (max distance to polygon)
auto compareMax = [] (const Cell<T>& a, const Cell<T>& b) {
return a.max < b.max;
};
using Queue = std::priority_queue<Cell<T>, std::vector<Cell<T>>, decltype(compareMax)>;
Queue cellQueue(compareMax);
if (cellSize == 0) {
return envelope.min;
}
// cover polygon with initial cells
for (T x = envelope.min.x; x < envelope.max.x; x += cellSize) {
for (T y = envelope.min.y; y < envelope.max.y; y += cellSize) {
cellQueue.push(Cell<T>({x + h, y + h}, h, polygon));
}
}
// take centroid as the first best guess
auto bestCell = getCentroidCell(polygon);
// special case for rectangular polygons
Cell<T> bboxCell(envelope.min + size / 2.0, 0, polygon);
if (bboxCell.d > bestCell.d) {
bestCell = bboxCell;
}
auto numProbes = cellQueue.size();
while (!cellQueue.empty()) {
// pick the most promising cell from the queue
auto cell = cellQueue.top();
cellQueue.pop();
// update the best cell if we found a better one
if (cell.d > bestCell.d) {
bestCell = cell;
if (debug) std::cout << "found best " << ::round(1e4 * cell.d) / 1e4 << " after " << numProbes << " probes" << std::endl;
}
// do not drill down further if there's no chance of a better solution
if (cell.max - bestCell.d <= precision) continue;
// split the cell into four cells
h = cell.h / 2;
cellQueue.push(Cell<T>({cell.c.x - h, cell.c.y - h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x + h, cell.c.y - h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x - h, cell.c.y + h}, h, polygon));
cellQueue.push(Cell<T>({cell.c.x + h, cell.c.y + h}, h, polygon));
numProbes += 4;
}
if (debug) {
std::cout << "num probes: " << numProbes << std::endl;
std::cout << "best distance: " << bestCell.d << std::endl;
}
return bestCell.c;
}
} // namespace mapbox
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
// Based on variant/recursive_wrapper.hpp from boost.
//
// Original license:
//
// Copyright (c) 2002-2003
// Eric Friedman, Itay Maman
//
// 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)
#include <cassert>
#include <utility>
namespace mapbox {
namespace util {
template <typename T>
class recursive_wrapper
{
T* p_;
void assign(T const& rhs)
{
this->get() = rhs;
}
public:
using type = T;
/**
* Default constructor default initializes the internally stored value.
* For POD types this means nothing is done and the storage is
* uninitialized.
*
* @throws std::bad_alloc if there is insufficient memory for an object
* of type T.
* @throws any exception thrown by the default constructur of T.
*/
recursive_wrapper()
: p_(new T){};
~recursive_wrapper() noexcept { delete p_; };
recursive_wrapper(recursive_wrapper const& operand)
: p_(new T(operand.get())) {}
recursive_wrapper(T const& operand)
: p_(new T(operand)) {}
recursive_wrapper(recursive_wrapper&& operand)
: p_(new T(std::move(operand.get()))) {}
recursive_wrapper(T&& operand)
: p_(new T(std::move(operand))) {}
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
{
assign(rhs.get());
return *this;
}
inline recursive_wrapper& operator=(T const& rhs)
{
assign(rhs);
return *this;
}
inline void swap(recursive_wrapper& operand) noexcept
{
T* temp = operand.p_;
operand.p_ = p_;
p_ = temp;
}
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
{
swap(rhs);
return *this;
}
recursive_wrapper& operator=(T&& rhs)
{
get() = std::move(rhs);
return *this;
}
T& get()
{
assert(p_);
return *get_pointer();
}
T const& get() const
{
assert(p_);
return *get_pointer();
}
T* get_pointer() { return p_; }
const T* get_pointer() const { return p_; }
operator T const&() const { return this->get(); }
operator T&() { return this->get(); }
}; // class recursive_wrapper
template <typename T>
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
#ifndef MAPBOX_UTIL_VARIANT_HPP
#define MAPBOX_UTIL_VARIANT_HPP
#include <cassert>
#include <cstddef> // size_t
#include <new> // operator new
#include <stdexcept> // runtime_error
#include <string>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include "recursive_wrapper.hpp"
// clang-format off
// [[deprecated]] is only available in C++14, use this for the time being
#if __cplusplus <= 201103L
# ifdef __GNUC__
# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
# elif defined(_MSC_VER)
# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
# else
# define MAPBOX_VARIANT_DEPRECATED
# endif
#else
# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
#endif
#ifdef _MSC_VER
// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
#ifdef NDEBUG
#define VARIANT_INLINE __forceinline
#else
#define VARIANT_INLINE __declspec(noinline)
#endif
#else
#ifdef NDEBUG
#define VARIANT_INLINE inline __attribute__((always_inline))
#else
#define VARIANT_INLINE __attribute__((noinline))
#endif
#endif
// clang-format on
#define VARIANT_MAJOR_VERSION 1
#define VARIANT_MINOR_VERSION 1
#define VARIANT_PATCH_VERSION 0
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
namespace mapbox {
namespace util {
// XXX This should derive from std::logic_error instead of std::runtime_error.
// See https://github.com/mapbox/variant/issues/48 for details.
class bad_variant_access : public std::runtime_error
{
public:
explicit bad_variant_access(const std::string& what_arg)
: runtime_error(what_arg) {}
explicit bad_variant_access(const char* what_arg)
: runtime_error(what_arg) {}
}; // class bad_variant_access
template <typename R = void>
struct MAPBOX_VARIANT_DEPRECATED static_visitor
{
using result_type = R;
protected:
static_visitor() {}
~static_visitor() {}
};
namespace detail {
static constexpr std::size_t invalid_value = std::size_t(-1);
template <typename T, typename... Types>
struct direct_type;
template <typename T, typename First, typename... Types>
struct direct_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_same<T, First>::value
? sizeof...(Types)
: direct_type<T, Types...>::index;
};
template <typename T>
struct direct_type<T>
{
static constexpr std::size_t index = invalid_value;
};
template <typename T, typename... Types>
struct convertible_type;
template <typename T, typename First, typename... Types>
struct convertible_type<T, First, Types...>
{
static constexpr std::size_t index = std::is_convertible<T, First>::value
? sizeof...(Types)
: convertible_type<T, Types...>::index;
};
template <typename T>
struct convertible_type<T>
{
static constexpr std::size_t index = invalid_value;
};
template <typename T, typename... Types>
struct value_traits
{
using value_type = typename std::remove_reference<T>::type;
static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
static constexpr bool is_direct = direct_index != invalid_value;
static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
static constexpr bool is_valid = index != invalid_value;
static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
};
// check if T is in Types...
template <typename T, typename... Types>
struct has_type;
template <typename T, typename First, typename... Types>
struct has_type<T, First, Types...>
{
static constexpr bool value = std::is_same<T, First>::value || has_type<T, Types...>::value;
};
template <typename T>
struct has_type<T> : std::false_type
{
};
template <typename T, typename... Types>
struct is_valid_type;
template <typename T, typename First, typename... Types>
struct is_valid_type<T, First, Types...>
{
static constexpr bool value = std::is_convertible<T, First>::value || is_valid_type<T, Types...>::value;
};
template <typename T>
struct is_valid_type<T> : std::false_type
{
};
template <typename T, typename R = void>
struct enable_if_type
{
using type = R;
};
template <typename F, typename V, typename Enable = void>
struct result_of_unary_visit
{
using type = typename std::result_of<F(V&)>::type;
};
template <typename F, typename V>
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
template <typename F, typename V, typename Enable = void>
struct result_of_binary_visit
{
using type = typename std::result_of<F(V&, V&)>::type;
};
template <typename F, typename V>
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
{
using type = typename F::result_type;
};
template <std::size_t arg1, std::size_t... others>
struct static_max;
template <std::size_t arg>
struct static_max<arg>
{
static const std::size_t value = arg;
};
template <std::size_t arg1, std::size_t arg2, std::size_t... others>
struct static_max<arg1, arg2, others...>
{
static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
};
template <typename... Types>
struct variant_helper;
template <typename T, typename... Types>
struct variant_helper<T, Types...>
{
VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
{
if (type_index == sizeof...(Types))
{
reinterpret_cast<T*>(data)->~T();
}
else
{
variant_helper<Types...>::destroy(type_index, data);
}
}
VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
{
if (old_type_index == sizeof...(Types))
{
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
}
else
{
variant_helper<Types...>::move(old_type_index, old_value, new_value);
}
}
VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
{
if (old_type_index == sizeof...(Types))
{
new (new_value) T(*reinterpret_cast<const T*>(old_value));
}
else
{
variant_helper<Types...>::copy(old_type_index, old_value, new_value);
}
}
};
template <>
struct variant_helper<>
{
VARIANT_INLINE static void destroy(const std::size_t, void*) {}
VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
};
template <typename T>
struct unwrapper
{
static T const& apply_const(T const& obj) { return obj; }
static T& apply(T& obj) { return obj; }
};
template <typename T>
struct unwrapper<recursive_wrapper<T>>
{
static auto apply_const(recursive_wrapper<T> const& obj)
-> typename recursive_wrapper<T>::type const&
{
return obj.get();
}
static auto apply(recursive_wrapper<T>& obj)
-> typename recursive_wrapper<T>::type&
{
return obj.get();
}
};
template <typename T>
struct unwrapper<std::reference_wrapper<T>>
{
static auto apply_const(std::reference_wrapper<T> const& obj)
-> typename std::reference_wrapper<T>::type const&
{
return obj.get();
}
static auto apply(std::reference_wrapper<T>& obj)
-> typename std::reference_wrapper<T>::type&
{
return obj.get();
}
};
template <typename F, typename V, typename R, typename... Types>
struct dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types>
struct dispatcher<F, V, R, T, Types...>
{
VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
if (v.template is<T>())
{
return f(unwrapper<T>::apply_const(v.template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& v, F&& f)
{
if (v.template is<T>())
{
return f(unwrapper<T>::apply(v.template get<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T>
struct dispatcher<F, V, R, T>
{
VARIANT_INLINE static R apply_const(V const& v, F&& f)
{
return f(unwrapper<T>::apply_const(v.template get<T>()));
}
VARIANT_INLINE static R apply(V& v, F&& f)
{
return f(unwrapper<T>::apply(v.template get<T>()));
}
};
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_rhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
if (rhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
if (rhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T0, typename T1>
struct binary_dispatcher_rhs<F, V, R, T0, T1>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
return f(unwrapper<T0>::apply_const(lhs.template get<T0>()),
unwrapper<T1>::apply_const(rhs.template get<T1>()));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
return f(unwrapper<T0>::apply(lhs.template get<T0>()),
unwrapper<T1>::apply(rhs.template get<T1>()));
}
};
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher_lhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
if (lhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
if (lhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>()));
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
}
}
};
template <typename F, typename V, typename R, typename T0, typename T1>
struct binary_dispatcher_lhs<F, V, R, T0, T1>
{
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
{
return f(unwrapper<T1>::apply_const(lhs.template get<T1>()),
unwrapper<T0>::apply_const(rhs.template get<T0>()));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
return f(unwrapper<T1>::apply(lhs.template get<T1>()),
unwrapper<T0>::apply(rhs.template get<T0>()));
}
};
template <typename F, typename V, typename R, typename... Types>
struct binary_dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types>
struct binary_dispatcher<F, V, R, T, Types...>
{
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
if (v0.template is<T>())
{
if (v1.template is<T>())
{
return f(unwrapper<T>::apply_const(v0.template get<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
}
else if (v1.template is<T>())
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
if (v0.template is<T>())
{
if (v1.template is<T>())
{
return f(unwrapper<T>::apply(v0.template get<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
}
else if (v1.template is<T>())
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
};
template <typename F, typename V, typename R, typename T>
struct binary_dispatcher<F, V, R, T>
{
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
{
return f(unwrapper<T>::apply_const(v0.template get<T>()),
unwrapper<T>::apply_const(v1.template get<T>())); // call binary functor
}
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
return f(unwrapper<T>::apply(v0.template get<T>()),
unwrapper<T>::apply(v1.template get<T>())); // call binary functor
}
};
// comparator functors
struct equal_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs == rhs;
}
};
struct less_comp
{
template <typename T>
bool operator()(T const& lhs, T const& rhs) const
{
return lhs < rhs;
}
};
template <typename Variant, typename Comp>
class comparer
{
public:
explicit comparer(Variant const& lhs) noexcept
: lhs_(lhs) {}
comparer& operator=(comparer const&) = delete;
// visitor
template <typename T>
bool operator()(T const& rhs_content) const
{
T const& lhs_content = lhs_.template get<T>();
return Comp()(lhs_content, rhs_content);
}
private:
Variant const& lhs_;
};
// True if Predicate matches for all of the types Ts
template <template <typename> class Predicate, typename... Ts>
struct static_all_of : std::is_same<std::tuple<std::true_type, typename Predicate<Ts>::type...>,
std::tuple<typename Predicate<Ts>::type..., std::true_type>>
{
};
// True if Predicate matches for none of the types Ts
template <template <typename> class Predicate, typename... Ts>
struct static_none_of : std::is_same<std::tuple<std::false_type, typename Predicate<Ts>::type...>,
std::tuple<typename Predicate<Ts>::type..., std::false_type>>
{
};
} // namespace detail
struct no_init
{
};
template <typename... Types>
class variant
{
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
static_assert(detail::static_none_of<std::is_reference, Types...>::value, "Variant can not hold reference types. Maybe use std::reference?");
private:
static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
using data_type = typename std::aligned_storage<data_size, data_align>::type;
using helper_type = detail::variant_helper<Types...>;
std::size_t type_index;
data_type data;
public:
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
: type_index(sizeof...(Types)-1)
{
static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
new (&data) first_type();
}
VARIANT_INLINE variant(no_init) noexcept
: type_index(detail::invalid_value) {}
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
template <typename T, typename Traits = detail::value_traits<T, Types...>,
typename Enable = typename std::enable_if<Traits::is_valid>::type>
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
: type_index(Traits::index)
{
new (&data) typename Traits::target_type(std::forward<T>(val));
}
VARIANT_INLINE variant(variant<Types...> const& old)
: type_index(old.type_index)
{
helper_type::copy(old.type_index, &old.data, &data);
}
VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
: type_index(old.type_index)
{
helper_type::move(old.type_index, &old.data, &data);
}
private:
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::copy(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
helper_type::move(rhs.type_index, &rhs.data, &data);
type_index = rhs.type_index;
}
public:
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
{
move_assign(std::move(other));
return *this;
}
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
{
copy_assign(other);
return *this;
}
// conversions
// move-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
{
variant<Types...> temp(std::forward<T>(rhs));
move_assign(std::move(temp));
return *this;
}
// copy-assign
template <typename T>
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
{
variant<Types...> temp(rhs);
copy_assign(temp);
return *this;
}
template <typename T>
VARIANT_INLINE bool is() const
{
static_assert(detail::has_type<T, Types...>::value, "invalid type in T in `is<T>()` for this variant");
return type_index == detail::direct_type<T, Types...>::index;
}
VARIANT_INLINE bool valid() const
{
return type_index != detail::invalid_value;
}
template <typename T, typename... Args>
VARIANT_INLINE void set(Args&&... args)
{
helper_type::destroy(type_index, &data);
type_index = detail::invalid_value;
new (&data) T(std::forward<Args>(args)...);
type_index = detail::direct_type<T, Types...>::index;
}
// get<T>()
template <typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<T, Types...>::index)
{
return *reinterpret_cast<T*>(&data);
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<T, Types...>::index)
{
return *reinterpret_cast<T const*>(&data);
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as recursive_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// get<T>() - T stored as std::reference_wrapper<T>
template <typename T, typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T& get()
{
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
template <typename T, typename std::enable_if<
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
VARIANT_INLINE T const& get() const
{
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
{
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
}
else
{
throw bad_variant_access("in get<T>()");
}
}
// This function is deprecated because it returns an internal index field.
// Use which() instead.
MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
{
return type_index;
}
VARIANT_INLINE int which() const noexcept
{
return static_cast<int>(sizeof...(Types)-type_index - 1);
}
// visitor
// unary
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
auto VARIANT_INLINE static visit(V const& v, F&& f)
-> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
{
return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
auto VARIANT_INLINE static visit(V& v, F&& f)
-> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
{
return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
}
// binary
// const
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
{
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
}
// non-const
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
{
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
}
~variant() noexcept // no-throw destructor
{
helper_type::destroy(type_index, &data);
}
// comparison operators
// equality
VARIANT_INLINE bool operator==(variant const& rhs) const
{
assert(valid() && rhs.valid());
if (this->which() != rhs.which())
{
return false;
}
detail::comparer<variant, detail::equal_comp> visitor(*this);
return visit(rhs, visitor);
}
VARIANT_INLINE bool operator!=(variant const& rhs) const
{
return !(*this == rhs);
}
// less than
VARIANT_INLINE bool operator<(variant const& rhs) const
{
assert(valid() && rhs.valid());
if (this->which() != rhs.which())
{
return this->which() < rhs.which();
}
detail::comparer<variant, detail::less_comp> visitor(*this);
return visit(rhs, visitor);
}
VARIANT_INLINE bool operator>(variant const& rhs) const
{
return rhs < *this;
}
VARIANT_INLINE bool operator<=(variant const& rhs) const
{
return !(*this > rhs);
}
VARIANT_INLINE bool operator>=(variant const& rhs) const
{
return !(*this < rhs);
}
};
// unary visitor interface
// const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
return V::visit(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
return V::visit(v, std::forward<F>(f));
}
// binary visitor interface
// const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
return V::binary_visit(v0, v1, std::forward<F>(f));
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
return V::binary_visit(v0, v1, std::forward<F>(f));
}
// getter interface
template <typename ResultType, typename T>
ResultType& get(T& var)
{
return var.template get<ResultType>();
}
template <typename ResultType, typename T>
ResultType const& get(T const& var)
{
return var.template get<ResultType>();
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_HPP
#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
#define MAPBOX_UTIL_VARIANT_IO_HPP
#include <iosfwd>
#include "variant.hpp"
namespace mapbox {
namespace util {
namespace detail {
// operator<< helper
template <typename Out>
class printer
{
public:
explicit printer(Out& out)
: out_(out) {}
printer& operator=(printer const&) = delete;
// visitor
template <typename T>
void operator()(T const& operand) const
{
out_ << operand;
}
private:
Out& out_;
};
}
// operator<<
template <typename CharT, typename Traits, typename... Types>
VARIANT_INLINE std::basic_ostream<CharT, Traits>&
operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
{
detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
apply_visitor(visitor, rhs);
return out;
}
} // namespace util
} // namespace mapbox
#endif // MAPBOX_UTIL_VARIANT_IO_HPP
#include <iostream>
#include "snake.h"
#include "clipper/clipper.hpp"
#define CLIPPER_SCALE 10000
using namespace snake_geometry;
using namespace std;
namespace bg = boost::geometry;
namespace trans = bg::strategy::transform;
namespace snake {
Scenario::Scenario() :
_mAreaBoundingBox(min_bbox_rt{0, 0, 0, BoostPolygon{}})
{
}
bool Scenario::addArea(Area &area)
{
if (area.geoPolygon.size() < 3){
errorString = "Area has less than three vertices.";
return false;
}
if (area.type == MeasurementArea)
return Scenario::_setMeasurementArea(area);
else if (area.type == ServiceArea)
return Scenario::_setServiceArea(area);
else if (area.type == Corridor)
return Scenario::_setCorridor(area);
return false;
}
bool Scenario::defined(double tileWidth, double tileHeight, double minTileArea)
{
if (!_areas2enu())
return false;
if (!_calculateBoundingBox())
return false;
if (!_calculateTiles(tileWidth, tileHeight, minTileArea))
return false;
if (!_calculateJoinedArea())
return false;
return true;
}
bool Scenario::_areas2enu()
{
if (_measurementArea.geoPolygon.size() > 0){
_measurementAreaENU.clear();
for(auto vertex : _measurementArea.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _measurementArea.altitude}, ENUVertex);
_measurementAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
bg::correct(_measurementAreaENU);
_serviceAreaENU.clear();
if (_serviceArea.geoPolygon.size() > 0){
for(auto vertex : _serviceArea.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _serviceArea.altitude}, ENUVertex);
_serviceAreaENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
} else{
errorString = "Service area has no vertices.";
return false;
}
bg::correct(_serviceAreaENU);
polygonCenter(_serviceAreaENU, _homePositionENU);
_corridorENU.clear();
if (_corridor.geoPolygon.size() > 0){
for(auto vertex : _corridor.geoPolygon) {
Point3D ENUVertex;
toENU(_geoOrigin, Point3D{vertex[0], vertex[1], _corridor.altitude}, ENUVertex);
_corridorENU.outer().push_back(BoostPoint{ENUVertex[0], ENUVertex[1]});
}
}
bg::correct(_corridorENU);
return true;
}
errorString = "Measurement area has no vertices.";
return false;
}
bool Scenario::_setMeasurementArea(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
GeoPoint2D origin2D = area.geoPolygon[0];
_geoOrigin = GeoPoint3D{origin2D[0], origin2D[1], 0};
_measurementArea = area;
_measurementAreaENU.clear();
_serviceAreaENU.clear();
_corridorENU.clear();
return true;
}
bool Scenario::_setServiceArea(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
_serviceArea = area;
_serviceAreaENU.clear();
return true;
}
bool Scenario::_setCorridor(Area &area)
{
if (area.geoPolygon.size() <= 0)
return false;
_corridor = area;
_corridorENU.clear();
return true;
}
bool Scenario::_calculateBoundingBox()
{
minimalBoundingBox(_measurementAreaENU, _mAreaBoundingBox);
return true;
}
/**
* Devides the (measurement area) bounding box into tiles and clips it to the measurement area.
*
* Devides the (measurement area) bounding box into tiles of width \p tileWidth and height \p tileHeight.
* Clips the resulting tiles to the measurement area. Tiles are rejected, if their area is smaller than \p minTileArea.
* The function assumes that \a _measurementAreaENU and \a _mAreaBoundingBox have correct values. \see \ref Scenario::_areas2enu() and \ref
* Scenario::_calculateBoundingBox().
*
* @param tileWidth The width (>0) of a tile.
* @param tileHeight The heigth (>0) of a tile.
* @param minTileArea The minimal area (>0) of a tile.
*
* @return Returns true if successful.
*/
bool Scenario::_calculateTiles(double tileWidth, double tileHeight, double minTileArea)
{
_tilesENU.clear();
_tileCenterPointsENU.clear();
if (tileWidth <= 0 || tileHeight <= 0 || minTileArea <= 0) {
errorString = "Parameters tileWidth, tileHeight, minTileArea must be positive.";
return false;
}
double bbox_width = _mAreaBoundingBox.width;
double bbox_height = _mAreaBoundingBox.height;
BoostPoint origin = _mAreaBoundingBox.corners.outer()[0];
//cout << "Origin: " << origin[0] << " " << origin[1] << endl;
// Transform _measurementAreaENU polygon to bounding box coordinate system.
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate(_mAreaBoundingBox.angle*180/M_PI);
trans::translate_transformer<double, 2, 2> translate(-origin.get<0>(), -origin.get<1>());
BoostPolygon translated_polygon;
BoostPolygon rotated_polygon;
boost::geometry::transform(_measurementAreaENU, translated_polygon, translate);
boost::geometry::transform(translated_polygon, rotated_polygon, rotate);
bg::correct(rotated_polygon);
//cout << bg::wkt<BoostPolygon2D>(rotated_polygon) << endl;
size_t i_max = ceil(bbox_width/tileWidth);
size_t j_max = ceil(bbox_height/tileHeight);
if (i_max < 1 || j_max < 1) {
errorString = "tileWidth or tileHeight to small.";
return false;
}
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate_back(-_mAreaBoundingBox.angle*180/M_PI);
trans::translate_transformer<double, 2, 2> translate_back(origin.get<0>(), origin.get<1>());
for (size_t i = 0; i < i_max; ++i){
double x_min = tileWidth*i;
double x_max = x_min + tileWidth;
for (size_t j = 0; j < j_max; ++j){
double y_min = tileHeight*j;
double y_max = y_min + tileHeight;
BoostPolygon tile_unclipped;
tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});
tile_unclipped.outer().push_back(BoostPoint{x_min, y_max});
tile_unclipped.outer().push_back(BoostPoint{x_max, y_max});
tile_unclipped.outer().push_back(BoostPoint{x_max, y_min});
tile_unclipped.outer().push_back(BoostPoint{x_min, y_min});
std::deque<BoostPolygon> boost_tiles;
if (!boost::geometry::intersection(tile_unclipped, rotated_polygon, boost_tiles))
continue;
for (BoostPolygon t : boost_tiles)
{
if (bg::area(t) > minTileArea){
// Transform boost_tile to world coordinate system.
BoostPolygon rotated_tile;
BoostPolygon translated_tile;
boost::geometry::transform(t, rotated_tile, rotate_back);
boost::geometry::transform(rotated_tile, translated_tile, translate_back);
// Store tile and calculate center point.
_tilesENU.push_back(translated_tile);
BoostPoint tile_center;
polygonCenter(translated_tile, tile_center);
_tileCenterPointsENU.push_back(tile_center);
}
}
}
}
if (_tilesENU.size() < 1){
errorString = "No tiles calculated. Is the minTileArea parameter large enough?";
return false;
}
return true;
}
bool Scenario::_calculateJoinedArea()
{
_joinedAreaENU.clear();
// Measurement area and service area overlapping?
bool overlapingSerMeas = bg::intersects(_measurementAreaENU, _serviceAreaENU) ? true : false;
bool corridorValid = _corridorENU.outer().size() > 0 ? true : false;
// Check if corridor is connecting measurement area and service area.
bool corridor_is_connection = false;
if (corridorValid) {
// Corridor overlaping with measurement area?
if ( bg::intersects(_corridorENU, _measurementAreaENU) ) {
// Corridor overlaping with service area?
if ( bg::intersects(_corridorENU, _serviceAreaENU) )
corridor_is_connection = true;
}
}
// Are areas joinable?
std::deque<BoostPolygon> sol;
BoostPolygon partialArea = _measurementAreaENU;
if (overlapingSerMeas){
if(corridor_is_connection){
bg::union_(partialArea, _corridorENU, sol);
}
} else if (corridor_is_connection){
bg::union_(partialArea, _corridorENU, sol);
} else {
errorString = "Areas are not overlapping";
return false;
}
if (sol.size() > 0) {
partialArea = sol[0];
sol.clear();
}
// Join areas.
bg::union_(partialArea, _serviceAreaENU, sol);
if (sol.size() > 0) {
_joinedAreaENU = sol[0];
} else {
return false;
}
return true;
}
FlightPlan::FlightPlan()
{
}
bool FlightPlan::generate(double lineDistance, double minTransectLength)
{
_waypointsENU.clear();
_waypoints.clear();
_arrivalPathIdx.clear();
_returnPathIdx.clear();
#ifndef NDEBUG
_PathVertices.clear();
#endif
auto start = std::chrono::high_resolution_clock::now();
if (!_generateTransects(lineDistance, minTransectLength))
return false;
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << endl;
cout << "Execution time _generateTransects(): " << delta.count() << " ms" << endl;
//=======================================
// Route Transects using Google or-tools.
//=======================================
// Offset joined area.
const BoostPolygon &jArea = _scenario.getJoineAreaENU();
BoostPolygon jAreaOffset;
offsetPolygon(jArea, jAreaOffset, detail::offsetConstant);
// Create vertex list;
BoostLineString vertices;
size_t n_t = _transects.size()*2;
size_t n0 = n_t+1;
vertices.reserve(n0);
for (auto lstring : _transects){
for (auto vertex : lstring){
vertices.push_back(vertex);
}
}
vertices.push_back(_scenario.getHomePositonENU());
for (long i=0; i<long(jArea.outer().size())-1; ++i) {
vertices.push_back(jArea.outer()[i]);
}
for (auto ring : jArea.inners()) {
for (auto vertex : ring)
vertices.push_back(vertex);
}
size_t n1 = vertices.size();
// Generate routing model.
RoutingDataModel_t dataModel;
Matrix<double> connectionGraph(n1, n1);
start = std::chrono::high_resolution_clock::now();
_generateRoutingModel(vertices, jAreaOffset, n0, dataModel, connectionGraph);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << "Execution time _generateRoutingModel(): " << delta.count() << " ms" << endl;
// Create Routing Index Manager.
RoutingIndexManager manager(dataModel.distanceMatrix.getN(), dataModel.numVehicles,
dataModel.depot);
// Create Routing Model.
RoutingModel routing(manager);
// Create and register a transit callback.
const int transit_callback_index = routing.RegisterTransitCallback(
[&dataModel, &manager](int64 from_index, int64 to_index) -> int64 {
// Convert from routing variable Index to distance matrix NodeIndex.
auto from_node = manager.IndexToNode(from_index).value();
auto to_node = manager.IndexToNode(to_index).value();
return dataModel.distanceMatrix.get(from_node, to_node);
});
// Define Constraints.
size_t n = _transects.size()*2;
Solver *solver = routing.solver();
for (size_t i=0; i<n; i=i+2){
// auto idx0 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i));
// auto idx1 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i+1));
// auto cond0 = routing.NextVar(idx0)->IsEqual(idx1);
// auto cond1 = routing.NextVar(idx1)->IsEqual(idx0);
// auto c = solver->MakeNonEquality(cond0, cond1);
// solver->AddConstraint(c);
// alternative
auto idx0 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i));
auto idx1 = manager.NodeToIndex(RoutingIndexManager::NodeIndex(i+1));
auto cond0 = routing.NextVar(idx0)->IsEqual(idx1);
auto cond1 = routing.NextVar(idx1)->IsEqual(idx0);
vector<IntVar*> conds{cond0, cond1};
auto c = solver->MakeAllDifferent(conds);
solver->MakeRejectFilter();
solver->AddConstraint(c);
}
// Define cost of each arc.
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index);
// Setting first solution heuristic.
RoutingSearchParameters searchParameters = DefaultRoutingSearchParameters();
searchParameters.set_first_solution_strategy(
FirstSolutionStrategy::PATH_CHEAPEST_ARC);
google::protobuf::Duration *tMax = new google::protobuf::Duration(); // seconds
tMax->set_seconds(10);
searchParameters.set_allocated_time_limit(tMax);
// Solve the problem.
start = std::chrono::high_resolution_clock::now();
const Assignment* solution = routing.SolveWithParameters(searchParameters);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
cout << "Execution time routing.SolveWithParameters(): " << delta.count() << " ms" << endl;
if (!solution || solution->Size() <= 1){
errorString = "Not able to solve the routing problem.";
return false;
}
// Extract waypoints from solution.
long index = routing.Start(0);
std::vector<size_t> route;
route.push_back(manager.IndexToNode(index).value());
while (!routing.IsEnd(index)){
index = solution->Value(routing.NextVar(index));
route.push_back(manager.IndexToNode(index).value());
}
// Connect transects
#ifndef NDEBUG
_PathVertices = vertices;
#endif
{
_waypointsENU.push_back(vertices[route[0]]);
vector<size_t> pathIdx;
for (long i=0; i<long(route.size())-1; ++i){
size_t idx0 = route[i];
size_t idx1 = route[i+1];
pathIdx.clear();
shortestPathFromGraph(connectionGraph, idx0, idx1, pathIdx);
for (size_t j=1; j<pathIdx.size(); ++j)
_waypointsENU.push_back(vertices[pathIdx[j]]);
}
}
// Back transform waypoints.
GeoPoint3D origin{_scenario.getOrigin()};
for (auto vertex : _waypointsENU) {
GeoPoint3D geoVertex;
fromENU(origin, Point3D{vertex.get<0>(), vertex.get<1>(), 0}, geoVertex);
_waypoints.push_back(GeoPoint2D{geoVertex[0], geoVertex[1]});
}
// Reconstruct arrival path;
int i = 0;
for (; route[i] >= n_t; ++i)
_arrivalPathIdx.push_back(i);
_arrivalPathIdx.push_back(i); // vertex of first transect
// Reconstruct return path;
i = route.size()-1;
for (; route[i] >= n_t; --i)
_returnPathIdx.push_back(i);
_returnPathIdx.push_back(i); // vertex of last transect
return true;
}
bool FlightPlan::_generateTransects(double lineDistance, double minTransectLength)
{
_transects.clear();
if (_scenario.getTilesENU().size() != _progress.size()){
errorString = "Number of tiles is not equal to progress array length";
return false;
}
// Calculate processed tiles (_progress[i] == 100) and subtract them from measurement area.
size_t num_tiles = _progress.size();
vector<BoostPolygon> processedTiles;
{
const auto &tiles = _scenario.getTilesENU();
for (size_t i=0; i<num_tiles; ++i) {
if (_progress[i] == 100){
processedTiles.push_back(tiles[i]);
}
}
if (processedTiles.size() == num_tiles)
return true;
}
// Convert measurement area and tiles to clipper path.
ClipperLib::Path mAreaClipper;
for ( auto vertex : _scenario.getMeasurementAreaENU().outer() ){
mAreaClipper.push_back(ClipperLib::IntPoint{static_cast<ClipperLib::cInt>(vertex.get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>()*CLIPPER_SCALE)});
}
vector<ClipperLib::Path> processedTilesClipper;
for (auto t : processedTiles){
ClipperLib::Path path;
for (auto vertex : t.outer()){
path.push_back(ClipperLib::IntPoint{static_cast<ClipperLib::cInt>(vertex.get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(vertex.get<1>()*CLIPPER_SCALE)});
}
processedTilesClipper.push_back(path);
}
const min_bbox_rt &bbox = _scenario.getMeasurementAreaBBoxENU();
double alpha = bbox.angle;
double x0 = bbox.corners.outer()[0].get<0>();
double y0 = bbox.corners.outer()[0].get<1>();
double bboxWidth = bbox.width;
double bboxHeight = bbox.height;
double delta = detail::offsetConstant;
size_t num_t = int(ceil((bboxHeight + 2*delta)/lineDistance)); // number of transects
vector<double> yCoords;
yCoords.reserve(num_t);
double y = -delta;
for (size_t i=0; i < num_t; ++i) {
yCoords.push_back(y);
y += lineDistance;
}
// Generate transects and convert them to clipper path.
trans::rotate_transformer<boost::geometry::degree, double, 2, 2> rotate_back(-alpha*180/M_PI);
trans::translate_transformer<double, 2, 2> translate_back(x0, y0);
vector<ClipperLib::Path> transectsClipper;
transectsClipper.reserve(num_t);
for (size_t i=0; i < num_t; ++i) {
// calculate transect
BoostPoint v1{-delta, yCoords[i]};
BoostPoint v2{bboxWidth+delta, yCoords[i]};
BoostLineString transect;
transect.push_back(v1);
transect.push_back(v2);
// transform back
BoostLineString temp_transect;
bg::transform(transect, temp_transect, rotate_back);
transect.clear();
bg::transform(temp_transect, transect, translate_back);
ClipperLib::IntPoint c1{static_cast<ClipperLib::cInt>(transect[0].get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(transect[0].get<1>()*CLIPPER_SCALE)};
ClipperLib::IntPoint c2{static_cast<ClipperLib::cInt>(transect[1].get<0>()*CLIPPER_SCALE),
static_cast<ClipperLib::cInt>(transect[1].get<1>()*CLIPPER_SCALE)};
ClipperLib::Path path{c1, c2};
transectsClipper.push_back(path);
}
// Perform clipping.
// Clip transects to measurement area.
ClipperLib::Clipper clipper;
clipper.AddPath(mAreaClipper, ClipperLib::ptClip, true);
clipper.AddPaths(transectsClipper, ClipperLib::ptSubject, false);
ClipperLib::PolyTree clippedTransecsPolyTree1;
clipper.Execute(ClipperLib::ctIntersection, clippedTransecsPolyTree1, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Subtract holes (tiles with measurement_progress == 100) from transects.
clipper.Clear();
for (auto child : clippedTransecsPolyTree1.Childs)
clipper.AddPath(child->Contour, ClipperLib::ptSubject, false);
clipper.AddPaths(processedTilesClipper, ClipperLib::ptClip, true);
ClipperLib::PolyTree clippedTransecsPolyTree2;
clipper.Execute(ClipperLib::ctDifference, clippedTransecsPolyTree2, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
// Extract transects from PolyTree and convert them to BoostLineString
for (auto child : clippedTransecsPolyTree2.Childs){
ClipperLib::Path clipperTransect = child->Contour;
BoostPoint v1{static_cast<double>(clipperTransect[0].X)/CLIPPER_SCALE,
static_cast<double>(clipperTransect[0].Y)/CLIPPER_SCALE};
BoostPoint v2{static_cast<double>(clipperTransect[1].X)/CLIPPER_SCALE,
static_cast<double>(clipperTransect[1].Y)/CLIPPER_SCALE};
BoostLineString transect{v1, v2};
if (bg::length(transect) >= minTransectLength)
_transects.push_back(transect);
}
if (_transects.size() < 1)
return false;
return true;
}
void FlightPlan::_generateRoutingModel(const BoostLineString &vertices,
const BoostPolygon &polygonOffset,
size_t n0,
FlightPlan::RoutingDataModel_t &dataModel,
Matrix<double> &graph)
{
auto start = std::chrono::high_resolution_clock::now();
graphFromPolygon(polygonOffset, vertices, graph);
auto delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start);
cout << "Execution time graphFromPolygon(): " << delta.count() << " ms" << endl;
// cout << endl;
// for (size_t i=0; i<graph.size(); ++i){
// vector<double> &row = graph[i];
// for (size_t j=0; j<row.size();++j){
// cout << "(" << i << "," << j << "):" << row[j] << " ";
// }
// cout << endl;
// }
// cout << endl;
Matrix<double> distanceMatrix(graph);
start = std::chrono::high_resolution_clock::now();
toDistanceMatrix(distanceMatrix);
delta = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()-start);
cout << "Execution time toDistanceMatrix(): " << delta.count() << " ms" << endl;
dataModel.distanceMatrix.setDimension(n0, n0);
for (size_t i=0; i<n0; ++i){
dataModel.distanceMatrix.set(i, i, 0);
for (size_t j=i+1; j<n0; ++j){
dataModel.distanceMatrix.set(i, j, int64_t(distanceMatrix.get(i, j)*CLIPPER_SCALE));
dataModel.distanceMatrix.set(j, i, int64_t(distanceMatrix.get(i, j)*CLIPPER_SCALE));
}
}
dataModel.numVehicles = 1;
dataModel.depot = n0-1;
}
}
#pragma once
#include <vector>
#include <string>
#include <array>
#include "snake_geometry.h"
#include "ortools/constraint_solver/routing.h"
#include "ortools/constraint_solver/routing_enums.pb.h"
#include "ortools/constraint_solver/routing_index_manager.h"
#include "ortools/constraint_solver/routing_parameters.h"
using namespace std;
using namespace snake_geometry;
using namespace operations_research;
namespace snake {
enum AreaType {MeasurementArea, ServiceArea, Corridor};
struct Area {
GeoPoint2DList geoPolygon;
double altitude;
size_t layers;
AreaType type;
};
//========================================================================================
// Scenario
//========================================================================================
class Scenario{
public:
Scenario();
bool addArea(Area &area);
const Area &getMeasurementArea() const {return _measurementArea;}
const Area &getServiceArea() const {return _serviceArea;}
const Area &getCorridor() const {return _corridor;}
const BoostPolygon &getMeasurementAreaENU() {return _measurementAreaENU;}
const BoostPolygon &getServiceAreaENU() {return _serviceAreaENU;}
const BoostPolygon &getCorridorENU() {return _corridorENU;}
const BoostPolygon &getJoineAreaENU() {return _joinedAreaENU;}
const GeoPoint3D &getOrigin() {return _geoOrigin;}
const vector<BoostPolygon> &getTilesENU() {return _tilesENU;}
const BoostLineString &getTileCenterPointsENU() {return _tileCenterPointsENU;}
const min_bbox_rt &getMeasurementAreaBBoxENU() {return _mAreaBoundingBox;}
const BoostPoint &getHomePositonENU() {return _homePositionENU;}
bool defined(double tileWidth, double tileHeight, double minTileArea);
string errorString;
private:
bool _areas2enu();
bool _setMeasurementArea(Area &area);
bool _setServiceArea(Area &area);
bool _setCorridor(Area &area);
bool _calculateBoundingBox();
bool _calculateTiles(double tileWidth, double tileHeight, double minTileArea);
bool _calculateJoinedArea();
Area _measurementArea;
Area _serviceArea;
Area _corridor;
BoostPolygon _measurementAreaENU;
BoostPolygon _serviceAreaENU;
BoostPolygon _corridorENU;
BoostPolygon _joinedAreaENU;
min_bbox_rt _mAreaBoundingBox;
vector<BoostPolygon> _tilesENU;
BoostLineString _tileCenterPointsENU;
GeoPoint3D _geoOrigin;
BoostPoint _homePositionENU;
};
//========================================================================================
// FlightPlan
//========================================================================================
class FlightPlan{
public:
FlightPlan();
void setScenario(const Scenario &scenario) {_scenario = scenario;}
void setProgress(const vector<int8_t> &progress) {_progress = progress;}
const Scenario &getScenario(void) const {return _scenario;}
const BoostLineString &getWaypointsENU(void) const {return _waypointsENU;}
const GeoPoint2DList &getWaypoints(void) const {return _waypoints;}
const vector<uint64_t> &getArrivalPathIdx(void) const {return _arrivalPathIdx;}
const vector<uint64_t> &getReturnPathIdx(void) const {return _returnPathIdx;}
#ifndef NDEBUG
const BoostLineString &getPathVertices(void) const {return _PathVertices;}
#endif
bool generate(double lineDistance, double minTransectLength);
const vector<BoostLineString> &getTransects() const {return _transects;}
string errorString;
private:
// Search Filter to speed up routing.SolveWithParameters(...);
// Found here: http://www.lia.disi.unibo.it/Staff/MicheleLombardi/or-tools-doc/user_manual/manual/ls/ls_filtering.html
class SearchFilter : public LocalSearchFilter{
};
typedef struct{
Matrix<int64_t> distanceMatrix;
long numVehicles;
RoutingIndexManager::NodeIndex depot;
}RoutingDataModel_t;
bool _generateTransects(double lineDistance, double minTransectLength);
void _generateRoutingModel(const BoostLineString &vertices,
const BoostPolygon &polygonOffset,
size_t n0,
RoutingDataModel_t &dataModel,
Matrix<double> &graph);
Scenario _scenario;
BoostLineString _waypointsENU;
GeoPoint2DList _waypoints;
vector<BoostLineString> _transects;
vector<int8_t> _progress;
vector<uint64_t> _arrivalPathIdx;
vector<uint64_t> _returnPathIdx;
#ifndef NDEBUG
BoostLineString _PathVertices;
#endif
};
namespace detail {
const double offsetConstant = 0.1; // meter, polygon offset to compenstate for numerical inaccurracies.
}
}
#include "snake_geometry.h"
#include <mapbox/polylabel.hpp>
#include <mapbox/geometry.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/geometries/adapted/boost_tuple.hpp>
#include <GeographicLib/Geocentric.hpp>
#include <GeographicLib/LocalCartesian.hpp>
using namespace mapbox;
using namespace snake_geometry;
using namespace std;
namespace bg = bg;
namespace trans = bg::strategy::transform;
BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian)
namespace snake_geometry {
void toENU(const GeoPoint3D &WGS84Reference, const GeoPoint3D &WGS84Position, Point3D &ENUPosition)
{
GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f());
GeographicLib::LocalCartesian proj(WGS84Reference[0], WGS84Reference[1], WGS84Reference[2], earth);
proj.Forward(WGS84Position[0], WGS84Position[1], WGS84Position[2], ENUPosition[0], ENUPosition[1], ENUPosition[2]);
}
void fromENU(const Point3D &WGS84Reference, const Point3D &CartesianPosition, GeoPoint3D &GeoPosition)
{
GeographicLib::Geocentric earth(GeographicLib::Constants::WGS84_a(), GeographicLib::Constants::WGS84_f());
GeographicLib::LocalCartesian proj(WGS84Reference[0], WGS84Reference[1], WGS84Reference[2], earth);
proj.Reverse(CartesianPosition[0], CartesianPosition[1], CartesianPosition[2], GeoPosition[0], GeoPosition[1], GeoPosition[2]);
}
void polygonCenter(const BoostPolygon &polygon, BoostPoint &center)
{
if (polygon.outer().empty())
return;
geometry::polygon<double> p;
geometry::linear_ring<double> lr1;
for (size_t i = 0; i < polygon.outer().size(); ++i) {
geometry::point<double> vertex(polygon.outer()[i].get<0>(), polygon.outer()[i].get<1>());
lr1.push_back(vertex);
}
p.push_back(lr1);
geometry::point<double> c = polylabel(p);
center.set<0>(c.x);
center.set<1>(c.y);
}
void minimalBoundingBox(const BoostPolygon &polygon, min_bbox_rt &minBBox)
{
/*
Find the minimum-area bounding box of a set of 2D points
The input is a 2D convex hull, in an Nx2 numpy array of x-y co-ordinates.
The first and last points points must be the same, making a closed polygon.
This program finds the rotation angles of each edge of the convex polygon,
then tests the area of a bounding box aligned with the unique angles in
90 degrees of the 1st Quadrant.
Returns the
Tested with Python 2.6.5 on Ubuntu 10.04.4 (original version)
Results verified using Matlab
Copyright (c) 2013, David Butterworth, University of Queensland
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Willow Garage, Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
if (polygon.outer().empty())
return;
BoostPolygon convex_hull;
bg::convex_hull(polygon, convex_hull);
//cout << "Convex hull: " << bg::wkt<BoostPolygon2D>(convex_hull) << endl;
//# Compute edges (x2-x1,y2-y1)
std::vector<BoostPoint> edges;
auto convex_hull_outer = convex_hull.outer();
for (long i=0; i < long(convex_hull_outer.size())-1; ++i) {
BoostPoint p1 = convex_hull_outer.at(i);
BoostPoint p2 = convex_hull_outer.at(i+1);
double edge_x = p2.get<0>() - p1.get<0>();
double edge_y = p2.get<1>() - p1.get<1>();
edges.push_back(BoostPoint{edge_x, edge_y});
}
// cout << "Edges: ";
// for (auto e : edges)
// cout << e.get<0>() << " " << e.get<1>() << ",";
// cout << endl;
// Calculate unique edge angles atan2(y/x)
double angle_scale = 1e3;
std::set<long> angles_long;
for (auto vertex : edges) {
double angle = std::fmod(atan2(vertex.get<1>(), vertex.get<0>()), M_PI / 2);
angle = angle < 0 ? angle + M_PI / 2 : angle; // want strictly positive answers
angles_long.insert(long(round(angle*angle_scale)));
}
std::vector<double> edge_angles;
for (auto a : angles_long)
edge_angles.push_back(double(a)/angle_scale);
// cout << "Unique angles: ";
// for (auto e : edge_angles)
// cout << e*180/M_PI << ",";
// cout << endl;
double min_area = std::numeric_limits<double>::infinity();
// Test each angle to find bounding box with smallest area
// print "Testing", len(edge_angles), "possible rotations for bounding box... \n"
for (double angle : edge_angles){
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(angle*180/M_PI);
BoostPolygon hull_rotated;
bg::transform(convex_hull, hull_rotated, rotate);
//cout << "Convex hull rotated: " << bg::wkt<BoostPolygon2D>(hull_rotated) << endl;
bg::model::box<BoostPoint> box;
bg::envelope(hull_rotated, box);
// cout << "Bounding box: " << bg::wkt<bg::model::box<BoostPoint2D>>(box) << endl;
//# print "Rotated hull points are \n", rot_points
BoostPoint min_corner = box.min_corner();
BoostPoint max_corner = box.max_corner();
double min_x = min_corner.get<0>();
double max_x = max_corner.get<0>();
double min_y = min_corner.get<1>();
double max_y = max_corner.get<1>();
// cout << "min_x: " << min_x << endl;
// cout << "max_x: " << max_x << endl;
// cout << "min_y: " << min_y << endl;
// cout << "max_y: " << max_y << endl;
// Calculate height/width/area of this bounding rectangle
double width = max_x - min_x;
double height = max_y - min_y;
double area = width * height;
// cout << "Width: " << width << endl;
// cout << "Height: " << height << endl;
// cout << "area: " << area << endl;
// cout << "angle: " << angle*180/M_PI << endl;
// Store the smallest rect found first (a simple convex hull might have 2 answers with same area)
if (area < min_area){
min_area = area;
minBBox.angle = angle;
minBBox.width = width;
minBBox.height = height;
minBBox.corners.clear();
minBBox.corners.outer().push_back(BoostPoint{min_x, min_y});
minBBox.corners.outer().push_back(BoostPoint{min_x, max_y});
minBBox.corners.outer().push_back(BoostPoint{max_x, max_y});
minBBox.corners.outer().push_back(BoostPoint{max_x, min_y});
minBBox.corners.outer().push_back(BoostPoint{min_x, min_y});
}
//cout << endl << endl;
}
// Transform corners of minimal bounding box.
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(-minBBox.angle*180/M_PI);
BoostPolygon rotated_polygon;
bg::transform(minBBox.corners, rotated_polygon, rotate);
minBBox.corners = rotated_polygon;
}
void toBoost(const Point2D &point, BoostPoint &boost_point)
{
boost_point.set<0>(point[0]);
boost_point.set<1>(point[1]);
}
void fromBoost(const BoostPoint &boost_point, Point2D &point)
{
point[0] = boost_point.get<0>();
point[1] = boost_point.get<1>();
}
void toBoost(const Point2DList &point_list, BoostPolygon &boost_polygon)
{
for (auto vertex : point_list) {
BoostPoint boost_vertex;
toBoost(vertex, boost_vertex);
boost_polygon.outer().push_back(boost_vertex);
}
bg::correct(boost_polygon);
}
void fromBoost(const BoostPolygon &boost_polygon, Point2DList &point_list)
{
for (auto boost_vertex : boost_polygon.outer()) {
Point2D vertex;
fromBoost(boost_vertex, vertex);
point_list.push_back(vertex);
}
}
void rotateDeg(const Point2DList &point_list, Point2DList &rotated_point_list, double degree)
{
trans::rotate_transformer<bg::degree, double, 2, 2> rotate(degree);
BoostPolygon boost_polygon;
toBoost(point_list, boost_polygon);
BoostPolygon rotated_polygon;
bg::transform(boost_polygon, rotated_polygon, rotate);
fromBoost(rotated_polygon, rotated_point_list);
}
void rotateRad(const Point2DList &point_list, Point2DList &rotated_point_list, double rad)
{
rotateDeg(point_list, rotated_point_list, rad*180/M_PI);
}
bool isClockwise(const Point2DList &point_list)
{
double orientaion = 0;
double len = point_list.size();
for (long i=0; i < len-1; ++i){
Point2D v1 = point_list[i];
Point2D v2 = point_list[i+1];
orientaion += (v2[0]-v1[0])*(v2[1]+v1[1]);
}
Point2D v1 = point_list[len-1];
Point2D v2 = point_list[0];
orientaion += (v2[0]-v1[0])*(v2[1]+v1[1]);
return orientaion > 0 ? true : false;
}
void offsetPolygon(const BoostPolygon &polygon, BoostPolygon &polygonOffset, double offset)
{
bg::strategy::buffer::distance_symmetric<double> distance_strategy(offset);
bg::strategy::buffer::join_miter join_strategy(3);
bg::strategy::buffer::end_flat end_strategy;
bg::strategy::buffer::point_square point_strategy;
bg::strategy::buffer::side_straight side_strategy;
bg::model::multi_polygon<BoostPolygon> result;
bg::buffer(polygon, result, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy);
polygonOffset = result[0];
}
void graphFromPolygon(const BoostPolygon &polygon, const BoostLineString &vertices, Matrix<double> &graph)
{
size_t n = graph.getN();
for (size_t i=0; i < n; ++i) {
BoostPoint v1 = vertices[i];
for (size_t j=i+1; j < n; ++j){
BoostPoint v2 = vertices[j];
BoostLineString path{v1, v2};
double distance = 0;
if (!bg::within(path, polygon))
distance = std::numeric_limits<double>::infinity();
else
distance = bg::length(path);
graph.set(i, j, distance);
graph.set(j, i, distance);
}
}
}
bool dijkstraAlgorithm(const size_t numElements,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &elementPath,
std::function<double (const size_t, const size_t)> distanceDij)
{
if ( startIndex >= numElements
|| endIndex >= numElements
|| endIndex == startIndex) {
return false;
}
// Node struct
// predecessorIndex is the index of the predecessor node (nodeList[predecessorIndex])
// distance is the distance between the node and the start node
// node number is stored by the position in nodeList
struct Node{
int predecessorIndex = -1;
double distance = std::numeric_limits<double>::infinity();
};
// The list with all Nodes (elements)
std::vector<Node> nodeList(numElements);
// This list will be initalized with indices referring to the elements of nodeList.
// Elements will be successively remove during the execution of the Dijkstra Algorithm.
std::vector<size_t> workingSet(numElements);
//append elements to node list
for (size_t i = 0; i < numElements; ++i) workingSet[i] = i;
nodeList[startIndex].distance = 0;
// Dijkstra Algorithm
// https://de.wikipedia.org/wiki/Dijkstra-Algorithmus
while (workingSet.size() > 0) {
// serach Node with minimal distance
double minDist = std::numeric_limits<double>::infinity();
int minDistIndex_WS = -1; // WS = workinSet
for (size_t i = 0; i < workingSet.size(); ++i) {
const int nodeIndex = workingSet.at(i);
const double dist = nodeList.at(nodeIndex).distance;
if (dist < minDist) {
minDist = dist;
minDistIndex_WS = i;
}
}
if (minDistIndex_WS == -1)
return false;
size_t indexU_NL = workingSet.at(minDistIndex_WS); // NL = nodeList
workingSet.erase(workingSet.begin()+minDistIndex_WS);
if (indexU_NL == endIndex) // shortest path found
break;
const double distanceU = nodeList.at(indexU_NL).distance;
//update distance
for (size_t i = 0; i < workingSet.size(); ++i) {
int indexV_NL = workingSet[i]; // NL = nodeList
Node* v = &nodeList[indexV_NL];
double dist = distanceDij(indexU_NL, indexV_NL);
// is ther an alternative path which is shorter?
double alternative = distanceU + dist;
if (alternative < v->distance) {
v->distance = alternative;
v->predecessorIndex = indexU_NL;
}
}
}
// end Djikstra Algorithm
// reverse assemble path
int e = endIndex;
while (1) {
if (e == -1) {
if (elementPath[0] == startIndex)// check if starting point was reached
break;
return false;
}
elementPath.insert(elementPath.begin(), e);
//Update Node
e = nodeList[e].predecessorIndex;
}
return true;
}
void toDistanceMatrix(Matrix<double> &graph)
{
size_t n = graph.getN();
auto distance = [graph](size_t i, size_t j){
return graph.get(i,j);
};
std::vector<size_t> path;
for (size_t i=0; i < n; ++i) {
for (size_t j=i+1; j < n; ++j){
double d = graph.get(i,j);
if (!std::isinf(d))
continue;
path.clear();
bool ret = dijkstraAlgorithm(n, i, j, path, distance);
assert(ret);
(void)ret;
// cout << "(" << i << "," << j << ") d: " << d << endl;
// cout << "Path size: " << path.size() << endl;
// for (auto idx : path)
// cout << idx << " ";
// cout << endl;
d = 0;
for (long k=0; k < long(path.size())-1; ++k) {
size_t idx0 = path[k];
size_t idx1 = path[k+1];
double d0 = graph.get(idx0, idx1);
assert(std::isinf(d0) == false);
d += d0;
}
graph.set(i, j, d);
graph.set(j, i, d);
}
}
}
void shortestPathFromGraph(const Matrix<double> &graph, size_t startIndex, size_t endIndex, std::vector<size_t> &pathIdx)
{
if (!std::isinf(graph.get(startIndex, endIndex))){
pathIdx.push_back(startIndex);
pathIdx.push_back(endIndex);
} else {
auto distance = [graph](size_t i, size_t j){
return graph.get(i, j);
};
bool ret = dijkstraAlgorithm(graph.getN(), startIndex, endIndex, pathIdx, distance);
assert(ret);
(void)ret;
}
}
} // end namespace snake_geometry
#pragma once
#include <vector>
#include <array>
#include <boost/geometry.hpp>
#include <bits/stl_set.h>
namespace bg = boost::geometry;
namespace snake_geometry {
typedef std::array<double, 3> Point2D;
typedef std::array<double, 3> Point3D;
typedef std::array<double, 3> GeoPoint3D;
typedef std::array<double, 2> GeoPoint2D;
typedef std::vector<Point2D> Point2DList;
typedef std::vector<Point3D> Point3DList;
typedef std::vector<GeoPoint2D> GeoPoint2DList;
typedef std::vector<GeoPoint3D> GeoPoint3DList;
typedef bg::model::point<double, 2, bg::cs::cartesian> BoostPoint;
//typedef std::vector<BoostPoint> BoostPointList;
typedef bg::model::polygon<BoostPoint> BoostPolygon;
typedef bg::model::linestring<BoostPoint> BoostLineString;
typedef std::vector<std::vector<int64_t>> Int64Matrix;
template<class T>
class Matrix{
public:
Matrix() :
_elements(0),
_m(0),
_n(0),
_isInitialized(false)
{
}
Matrix(size_t m, size_t n) : Matrix(m, n, T{0}){}
Matrix(size_t m, size_t n, T value) :
_elements(m*n),
_m(m),
_n(n),
_isInitialized(true)
{
assert((m > 0) || (n > 0));
_matrix.resize(_elements, value);
}
double get(size_t i, size_t j) const
{
assert(_isInitialized);
assert(i < _m);
assert(j < _n);
return _matrix[i*_m+j];
}
size_t getM() const { return _m;}
size_t getN() const { return _n;}
void set(size_t i, size_t j, const T &value)
{
assert(_isInitialized);
assert(i < _m);
assert(j < _n);
_matrix[i*_m+j] = value;
}
void setDimension(size_t m, size_t n, const T &value)
{
assert((m > 0) || (n > 0));
assert(!_isInitialized);
if (!_isInitialized){
_m = m;
_n = n;
_elements = n*m;
_matrix.resize(_elements, value);
}
}
void setDimension(size_t m, size_t n)
{
assert((m > 0) || (n > 0));
assert(!_isInitialized);
if (!_isInitialized){
_m = m;
_n = n;
_elements = n*m;
_matrix.resize(_elements);
}
}
private:
size_t _elements;
size_t _m;
size_t _n;
bool _isInitialized;
std::vector<T> _matrix;
};
typedef struct {
double width;
double height;
double angle;
BoostPolygon corners;
}min_bbox_rt;
void toENU(const GeoPoint3D &WGS84Reference, const GeoPoint3D &WGS84Position, Point3D &ENUPosition);
void fromENU(const Point3D &WGS84Reference, const Point3D &ENUPosition, GeoPoint3D &WGS84Position);
void polygonCenter(const BoostPolygon &polygon, BoostPoint &center);
void minimalBoundingBox(const BoostPolygon &polygon, min_bbox_rt &minBBox);
void offsetPolygon(const BoostPolygon &polygon, BoostPolygon &polygonOffset, double offset);
void graphFromPolygon(const BoostPolygon &polygon, const BoostLineString &vertices, Matrix<double> &graph);
void toDistanceMatrix(Matrix<double> &graph);
bool dijkstraAlgorithm(const size_t numElements,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &elementPath,
std::function<double (const size_t, const size_t)> distanceDij);
void shortestPathFromGraph(const Matrix<double> &graph,
size_t startIndex,
size_t endIndex,
std::vector<size_t> &pathIdx);
void rotateDeg(const Point2DList &point_list, Point2DList &rotated_point_list, double degree);
void rotateRad(const Point2DList &point_list, Point2DList &rotated_point_list, double rad);
bool isClockwise(const Point2DList &point_list);
void toBoost(const Point2D &point, BoostPoint &boost_point);
void toBoost(const Point2DList &point_list, BoostPolygon &boost_polygon);
void fromBoost(const BoostPoint &boost_point, Point2D &point);
void fromBoost(const BoostPolygon &boost_polygon, Point2DList &point_list);
}
#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
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_TerrainQuery.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_ADSBVehicle.cpp"
#include "EWIEGA46WW/moc_GPSRTKFactGroup.cpp"
#include "EWIEGA46WW/moc_MAVLinkLogManager.cpp"
#include "EWIEGA46WW/moc_MultiVehicleManager.cpp"
#include "EWIEGA46WW/moc_SendMavCommandTest.cpp"
#include "EWIEGA46WW/moc_Vehicle.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_Bootloader.cpp"
#include "EWIEGA46WW/moc_FirmwareImage.cpp"
#include "EWIEGA46WW/moc_FirmwareUpgradeController.cpp"
#include "EWIEGA46WW/moc_JoystickConfigController.cpp"
#include "EWIEGA46WW/moc_PX4FirmwareUpgradeThread.cpp"
#include "EWIEGA46WW/moc_VehicleComponent.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_VideoItem.cpp"
#include "EWIEGA46WW/moc_VideoReceiver.cpp"
#include "EWIEGA46WW/moc_VideoSurface.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_CustomCommandWidget.cpp"
#include "EWIEGA46WW/moc_CustomCommandWidgetController.cpp"
#include "EWIEGA46WW/moc_ViewWidgetController.cpp"
......@@ -65,5 +65,40 @@
"shortDescription": "Reverses the phase direction. Phases go from high to low waypoint numbers, if checked.",
"type": "bool",
"defaultValue": false
},
{
"name": "SnakeTileWidth",
"shortDescription": "Snake: Tile Width.",
"type": "double",
"min" : 0.3,
"defaultValue": 5
},
{
"name": "SnakeTileHeight",
"shortDescription": "Snake: Tile Height.",
"type": "double",
"min" : 0.3,
"defaultValue": 5
},
{
"name": "SnakeMinTileArea",
"shortDescription": "Snake: Minimal Tile Area.",
"type": "double",
"min" : 0.1,
"defaultValue": 5
},
{
"name": "SnakeLineDistance",
"shortDescription": "Snake: Line Distance.",
"type": "double",
"min" : 0.3,
"defaultValue": 2
},
{
"name": "SnakeMinTransectLength",
"shortDescription": "Snake: Minimal Transect Length.",
"type": "double",
"min" : 0.3,
"defaultValue": 2
}
]
#include "WimaController.h"
#include "utilities.h"
#include "time.h"
const char* WimaController::wimaFileExtension = "wima";
const char* WimaController::areaItemsName = "AreaItems";
......@@ -14,6 +18,14 @@ const char* WimaController::flightSpeedName = "FlightSpeed";
const char* WimaController::arrivalReturnSpeedName = "ArrivalReturnSpeed";
const char* WimaController::altitudeName = "Altitude";
const char* WimaController::reverseName = "Reverse";
const char* WimaController::snakeTileWidthName = "SnakeTileWidth";
const char* WimaController::snakeTileHeightName = "SnakeTileHeight";
const char* WimaController::snakeMinTileAreaName = "SnakeMinTileAreaWidth";
const char* WimaController::snakeLineDistanceName = "SnakeLineDistance";
const char* WimaController::snakeMinTransectLengthName = "SnakeMinTransectLength";
using namespace snake;
using namespace snake_geometry;
WimaController::WimaController(QObject *parent)
: QObject (parent)
......@@ -47,26 +59,35 @@ WimaController::WimaController(QObject *parent)
, _vehicleHasLowBattery (false)
, _lowBatteryHandlingTriggered (false)
, _executingSmartRTL (false)
, _snakeConnectionStatus (SnakeConnectionStatus::Connected) // TODO: implement automatic connection
, _snakeCalcInProgress (false)
, _scenarioDefinedBool (false)
, _snakeTileWidth (settingsGroup, _metaDataMap[snakeTileWidthName])
, _snakeTileHeight (settingsGroup, _metaDataMap[snakeTileHeightName])
, _snakeMinTileArea (settingsGroup, _metaDataMap[snakeMinTileAreaName])
, _snakeLineDistance (settingsGroup, _metaDataMap[snakeLineDistanceName])
, _snakeMinTransectLength (settingsGroup, _metaDataMap[snakeMinTransectLengthName])
{
_showAllMissionItems.setRawValue(true);
_showCurrentMissionItems.setRawValue(true);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this, &WimaController::updateNextWaypoint);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this, &WimaController::recalcCurrentPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_flightSpeed, &Fact::rawValueChanged, this, &WimaController::updateflightSpeed);
connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this, &WimaController::updateArrivalReturnSpeed);
connect(&_altitude, &Fact::rawValueChanged, this, &WimaController::updateAltitude);
connect(&_reverse, &Fact::rawValueChanged, this, &WimaController::reverseChangedHandler);
connect(&_overlapWaypoints, &Fact::rawValueChanged, this, &WimaController::_updateNextWaypoint);
connect(&_maxWaypointsPerPhase, &Fact::rawValueChanged, this, &WimaController::_recalcCurrentPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
connect(&_flightSpeed, &Fact::rawValueChanged, this, &WimaController::_updateflightSpeed);
connect(&_arrivalReturnSpeed, &Fact::rawValueChanged, this, &WimaController::_updateArrivalReturnSpeed);
connect(&_altitude, &Fact::rawValueChanged, this, &WimaController::_updateAltitude);
connect(&_reverse, &Fact::rawValueChanged, this, &WimaController::_reverseChangedHandler);
// setup low battery handling
connect(&_checkBatteryTimer, &QTimer::timeout, this, &WimaController::checkBatteryLevel);
_checkBatteryTimer.setInterval(CHECK_BATTERY_INTERVAL);
connect(&_eventTimer, &QTimer::timeout, this, &WimaController::_eventTimerHandler);
_eventTimer.setInterval(EVENT_TIMER_INTERVAL);
Fact *enableLowBatteryHandling = qgcApp()->toolbox()->settingsManager()->wimaSettings()->enableLowBatteryHandling();
connect(enableLowBatteryHandling, &Fact::rawValueChanged, this, &WimaController::enableDisableLowBatteryHandling);
enableDisableLowBatteryHandling(enableLowBatteryHandling->rawValue());
connect(enableLowBatteryHandling, &Fact::rawValueChanged, this, &WimaController::_enableDisableLowBatteryHandling);
_enableDisableLowBatteryHandling(enableLowBatteryHandling->rawValue());
// Snake Worker Thread.
connect(&_snakeWorker, &SnakeWorker::resultReady, this, &WimaController::_snakeResultsReady);
}
QmlObjectListModel* WimaController::visualItems()
......@@ -161,6 +182,11 @@ Fact *WimaController::reverse()
return &_reverse;
}
Fact *WimaController::enableSnake()
{
return &_enableSnake;
}
bool WimaController::uploadOverrideRequired() const
{
return _uploadOverrideRequired;
......@@ -181,6 +207,16 @@ bool WimaController::vehicleHasLowBattery() const
return _vehicleHasLowBattery;
}
long WimaController::snakeConnectionStatus() const
{
return _snakeConnectionStatus;
}
bool WimaController::snakeCalcInProgress() const
{
return _snakeCalcInProgress;
}
Fact *WimaController::startWaypointIndex()
{
return &_nextPhaseStartWaypointIndex;
......@@ -208,11 +244,11 @@ void WimaController::setDataContainer(WimaDataContainer *container)
{
if (container != nullptr) {
if (_container != nullptr) {
disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
disconnect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::_fetchContainerData);
}
_container = container;
connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::fetchContainerData);
connect(_container, &WimaDataContainer::newDataAvailable, this, &WimaController::_fetchContainerData);
emit dataContainerChanged();
}
......@@ -229,7 +265,7 @@ void WimaController::setUploadOverrideRequired(bool overrideRequired)
void WimaController::nextPhase()
{
calcNextPhase();
_calcNextPhase();
}
void WimaController::previousPhase()
......@@ -476,7 +512,7 @@ bool WimaController::extractCoordinateList(QmlObjectListModel &missionItems, QVa
*
* \sa WimaDataContainer, WimaPlaner, WimaPlanData
*/
bool WimaController::fetchContainerData()
bool WimaController::_fetchContainerData()
{
// fetch only if valid, return true on sucess
......@@ -571,20 +607,47 @@ bool WimaController::fetchContainerData()
if (areaCounter != numAreas)
return false;
if (!setTakeoffLandPosition())
if (!_setTakeoffLandPosition())
return false;
updateWaypointPath();
_updateWaypointPath();
// set _nextPhaseStartWaypointIndex to 1
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
bool reverse = _reverse.rawValue().toBool();
_nextPhaseStartWaypointIndex.setRawValue(reverse? _missionItems.count() : int(1));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
if(!calcNextPhase())
if(!_calcNextPhase())
return false;
// Initialize _scenario.
Area mArea;
for (auto variant : _measurementArea.path()){
QGeoCoordinate c{variant.value<QGeoCoordinate>()};
mArea.geoPolygon.push_back(GeoPoint2D{c.latitude(), c.longitude()});
}
mArea.type = AreaType::MeasurementArea;
Area sArea;
for (auto variant : _serviceArea.path()){
QGeoCoordinate c{variant.value<QGeoCoordinate>()};
sArea.geoPolygon.push_back(GeoPoint2D{c.latitude(), c.longitude()});
}
sArea.type = AreaType::ServiceArea;
Area corridor;
for (auto variant : _corridor.path()){
QGeoCoordinate c{variant.value<QGeoCoordinate>()};
corridor.geoPolygon.push_back(GeoPoint2D{c.latitude(), c.longitude()});
}
corridor.type = AreaType::Corridor;
_scenario.addArea(mArea);
_scenario.addArea(sArea);
_scenario.addArea(corridor);
_verifyScenarioDefinedWithErrorMessage();
emit visualItemsChanged();
emit missionItemsChanged();
......@@ -592,7 +655,7 @@ bool WimaController::fetchContainerData()
return true;
}
bool WimaController::calcNextPhase()
bool WimaController::_calcNextPhase()
{
if (_missionItems.count() < 1) {
_startWaypointIndex = 0;
......@@ -660,7 +723,7 @@ bool WimaController::calcNextPhase()
// set start waypoint index for next phase
if (!lastMissionPhaseReached) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
if (!reverse) {
int untruncated = std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0);
int truncated = std::min(untruncated , _missionItems.count()-1);
......@@ -671,7 +734,7 @@ bool WimaController::calcNextPhase()
int truncated = std::max(untruncated , 0);
_nextPhaseStartWaypointIndex.setRawValue(truncated + 1);
}
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
}
// calculate path from home to first waypoint
......@@ -807,22 +870,22 @@ bool WimaController::calcNextPhase()
_setPhaseDistance(dist);
_setPhaseDuration(time);
_missionController->removeAll(); // remove items from _missionController, will be added on upload
updateAltitude();
_updateAltitude();
updateCurrentPath();
_updateCurrentPath();
emit currentMissionItemsChanged();
return true;
}
void WimaController::updateWaypointPath()
void WimaController::_updateWaypointPath()
{
_waypointPath.clear();
extractCoordinateList(_missionItems, _waypointPath, 0, _missionItems.count()-1);
emit waypointPathChanged();
}
void WimaController::updateCurrentPath()
void WimaController::_updateCurrentPath()
{
_currentWaypointPath.clear();
extractCoordinateList(_currentMissionItems, _currentWaypointPath, 0, _currentMissionItems.count()-1);
......@@ -830,24 +893,24 @@ void WimaController::updateCurrentPath()
emit currentWaypointPathChanged();
}
void WimaController::updateNextWaypoint()
void WimaController::_updateNextWaypoint()
{
if (_endWaypointIndex < _missionItems.count()-2) {
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(1 + std::max(_endWaypointIndex + 1 - _overlapWaypoints.rawValue().toInt(), 0));
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
}
}
void WimaController::recalcCurrentPhase()
void WimaController::_recalcCurrentPhase()
{
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(_startWaypointIndex + 1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
calcNextPhase();
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
_calcNextPhase();
}
bool WimaController::setTakeoffLandPosition()
bool WimaController::_setTakeoffLandPosition()
{
_takeoffLandPostion.setAltitude(0);
_takeoffLandPostion.setLongitude(_serviceArea.center().longitude());
......@@ -856,7 +919,7 @@ bool WimaController::setTakeoffLandPosition()
return true;
}
void WimaController::updateflightSpeed()
void WimaController::_updateflightSpeed()
{
int speedItemCounter = 0;
for (int i = 0; i < _currentMissionItems.count(); i++) {
......@@ -877,7 +940,7 @@ void WimaController::updateflightSpeed()
qWarning("WimaController::updateflightSpeed(): internal error.");
}
void WimaController::updateArrivalReturnSpeed()
void WimaController::_updateArrivalReturnSpeed()
{
int speedItemCounter = 0;
for (int i = 0; i < _currentMissionItems.count(); i++) {
......@@ -899,7 +962,7 @@ void WimaController::updateArrivalReturnSpeed()
}
void WimaController::updateAltitude()
void WimaController::_updateAltitude()
{
for (int i = 0; i < _currentMissionItems.count(); i++) {
SimpleMissionItem *item = _currentMissionItems.value<SimpleMissionItem *>(i);
......@@ -911,7 +974,7 @@ void WimaController::updateAltitude()
}
}
void WimaController::checkBatteryLevel()
void WimaController::_checkBatteryLevel()
{
Vehicle *managerVehicle = masterController()->managerVehicle();
WimaSettings* wimaSettings = qgcApp()->toolbox()->settingsManager()->wimaSettings();
......@@ -947,7 +1010,40 @@ void WimaController::checkBatteryLevel()
}
}
void WimaController::smartRTLCleanUp(bool flying)
void WimaController::_eventTimerHandler()
{
static EventTicker batteryLevelTicker(EVENT_TIMER_INTERVAL, CHECK_BATTERY_INTERVAL);
static EventTicker snakeEventLoopTicker(EVENT_TIMER_INTERVAL, SNAKE_EVENT_LOOP_INTERVAL);
// Battery level check necessary?
if ( batteryLevelTicker.ready() )
_checkBatteryLevel();
// Snake flight plan update necessary?
if ( snakeEventLoopTicker.ready() ) {
if ( _enableSnake.rawValue().toBool() && _localPlanDataValid && !_snakeCalcInProgress && _scenarioDefinedBool) {
long n = _scenario.getTilesENU().size();
QList<qint8> progress;
progress.reserve(n);
std::srand(time(NULL));
for (long i=0; i<n; ++i){
long r{rand()%200};
if ( r > 100 )
r = 100;
progress.append(qint8(r));
}
_snakeWorker.setScenario(_scenario);
_snakeWorker.setProgress(progress);
_snakeWorker.setLineDistance(_snakeLineDistance.rawValue().toDouble());
_snakeWorker.setMinTransectLength(_snakeMinTransectLength.rawValue().toDouble());
_snakeWorker.start();
}
}
}
void WimaController::_smartRTLCleanUp(bool flying)
{
if ( !flying) { // vehicle has landed
......@@ -959,27 +1055,27 @@ void WimaController::smartRTLCleanUp(bool flying)
_showAllMissionItems.setRawValue(true);
_missionController->removeAllFromVehicle();
_missionController->removeAll();
disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp);
disconnect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::_smartRTLCleanUp);
}
}
}
void WimaController::enableDisableLowBatteryHandling(QVariant enable)
void WimaController::_enableDisableLowBatteryHandling(QVariant enable)
{
if (enable.toBool()) {
_checkBatteryTimer.start();
_eventTimer.start();
} else {
_checkBatteryTimer.stop();
_eventTimer.stop();
}
}
void WimaController::reverseChangedHandler()
void WimaController::_reverseChangedHandler()
{
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
disconnect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
_nextPhaseStartWaypointIndex.setRawValue(_endWaypointIndex+1);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::calcNextPhase);
connect(&_nextPhaseStartWaypointIndex, &Fact::rawValueChanged, this, &WimaController::_calcNextPhase);
calcNextPhase();
_calcNextPhase();
}
void WimaController::_setPhaseDistance(double distance)
......@@ -1120,9 +1216,9 @@ bool WimaController::_calcReturnPath(QString &errorSring)
_setPhaseDistance(dist);
_setPhaseDuration(time);
_missionController->removeAll(); // remove items from _missionController, will be added on upload
updateAltitude();
_updateAltitude();
updateCurrentPath();
_updateCurrentPath();
emit currentMissionItemsChanged();
......@@ -1150,7 +1246,7 @@ void WimaController::_initSmartRTL()
if (_checkSmartRTLPreCondition(errorString) == true) {
_masterController->managerVehicle()->pauseVehicle();
connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::smartRTLCleanUp);
connect(masterController()->managerVehicle(), &Vehicle::flyingChanged, this, &WimaController::_smartRTLCleanUp);
if (_calcReturnPath(errorString)) {
_executingSmartRTL = true;
attemptCounter = 0;
......@@ -1184,6 +1280,44 @@ void WimaController::_executeSmartRTL()
masterController()->managerVehicle()->startMission();
}
void WimaController::_setSnakeConnectionStatus(WimaController::SnakeConnectionStatus status)
{
if (_snakeConnectionStatus != status) {
_snakeConnectionStatus = status;
emit snakeConnectionStatusChanged();
}
}
void WimaController::_setSnakeCalcInProgress(bool inProgress)
{
if (_snakeCalcInProgress != inProgress){
_snakeCalcInProgress = inProgress;
emit snakeCalcInProgressChanged();
}
}
bool WimaController::_verifyScenarioDefined()
{
_scenarioDefinedBool = _scenario.defined(_snakeTileWidth.rawValue().toDouble(), _snakeTileHeight.rawValue().toDouble(), _snakeMinTileArea.rawValue().toDouble());
return _scenarioDefinedBool;
}
bool WimaController::_verifyScenarioDefinedWithErrorMessage()
{
bool value = _verifyScenarioDefined();
if (!value){
QString errorString;
for (auto c : _scenario.errorString)
errorString.push_back(c);
qgcApp()->showMessage(errorString);
}
}
void WimaController::_snakeResultsReady(const WorkerResult_t &r)
{
// continue here
}
void WimaController::_loadCurrentMissionItemsFromBuffer()
{
_currentMissionItems.clear();
......@@ -1191,7 +1325,7 @@ void WimaController::_loadCurrentMissionItemsFromBuffer()
for (int i = 0; i < numItems; i++)
_currentMissionItems.append(_missionItemsBuffer.removeAt(0));
updateCurrentPath();
_updateCurrentPath();
}
......
......@@ -24,16 +24,18 @@
#include "WimaSettings.h"
#include "SettingsManager.h"
#include "snake/snake.h"
#include "snake.h"
#include "WimaControllerDetail.h"
#define CHECK_BATTERY_INTERVAL 1000
#define SMART_RTL_MAX_ATTEMPTS 3
#define CHECK_BATTERY_INTERVAL 1000 // ms
#define SMART_RTL_MAX_ATTEMPTS 3 // times
#define SMART_RTL_ATTEMPT_INTERVAL 200 // ms
#define EVENT_TIMER_INTERVAL 50 // ms
#define SNAKE_EVENT_LOOP_INTERVAL 50 // ms
using namespace snake;
class WimaController : public QObject
{
Q_OBJECT
......@@ -41,6 +43,10 @@ class WimaController : public QObject
enum FileType {WimaFile, PlanFile};
public:
enum SnakeConnectionStatus {Connected = 1, NotConnected = 0};
WimaController(QObject *parent = nullptr);
......@@ -71,6 +77,16 @@ public:
Q_PROPERTY(double phaseDuration READ phaseDuration NOTIFY phaseDurationChanged)
Q_PROPERTY(bool vehicleHasLowBattery READ vehicleHasLowBattery NOTIFY vehicleHasLowBatteryChanged)
// Snake
Q_PROPERTY(Fact* enableSnake READ enableSnake CONSTANT)
Q_PROPERTY(long snakeConnectionStatus READ snakeConnectionStatus NOTIFY snakeConnectionStatusChanged)
Q_PROPERTY(bool snakeCalcInProgress READ snakeCalcInProgress NOTIFY snakeCalcInProgressChanged)
Q_PROPERTY(Fact* snakeTileWidth READ snakeTileWidth CONSTANT)
Q_PROPERTY(Fact* snakeTileHeight READ snakeTileHeight CONSTANT)
Q_PROPERTY(Fact* snakeMinTileArea READ snakeMinTileArea CONSTANT)
Q_PROPERTY(Fact* snakeLineDistance READ snakeLineDistance CONSTANT)
Q_PROPERTY(Fact* snakeMinTransectLength READ snakeMinTransectLength CONSTANT)
// Property accessors
......@@ -95,13 +111,22 @@ public:
Fact* showCurrentMissionItems(void);
Fact* flightSpeed (void);
Fact* arrivalReturnSpeed (void);
Fact* altitude (void);
Fact* altitude (void);
Fact* reverse (void);
Fact* enableSnake (void);
Fact* snakeTileWidth (void) {return &_snakeTileWidth;}
Fact* snakeTileHeight (void) {return &_snakeTileHeight;}
Fact* snakeMinTileArea (void) {return &_snakeMinTileArea;}
Fact* snakeLineDistance (void) {return &_snakeLineDistance;}
Fact* snakeMinTransectLength (void) {return &_snakeMinTransectLength;}
bool uploadOverrideRequired (void) const;
double phaseDistance (void) const;
double phaseDuration (void) const;
bool vehicleHasLowBattery (void) const;
long snakeConnectionStatus (void) const;
bool snakeCalcInProgress (void) const;
// Property setters
void setMasterController (PlanMasterController* masterController);
......@@ -143,8 +168,13 @@ public:
static const char* showCurrentMissionItemsName;
static const char* flightSpeedName;
static const char* arrivalReturnSpeedName;
static const char* altitudeName;
static const char* altitudeName;
static const char* reverseName;
static const char* snakeTileWidthName;
static const char* snakeTileHeightName;
static const char* snakeMinTileAreaName;
static const char* snakeLineDistanceName;
static const char* snakeMinTransectLengthName;
// Member Methodes
QJsonDocument saveToJson(FileType fileType);
......@@ -176,25 +206,33 @@ signals:
void vehicleHasLowBatteryChanged (void);
void returnBatteryLowConfirmRequired (void);
void returnUserRequestConfirmRequired (void);
void snakeConnectionStatusChanged (void);
void snakeCalcInProgressChanged (void);
private:
enum SRTL_Reason {BatteryLow, UserRequest};
private slots:
bool fetchContainerData();
bool calcNextPhase(void);
void updateWaypointPath (void);
void updateCurrentPath (void);
void updateNextWaypoint (void);
void recalcCurrentPhase (void);
bool setTakeoffLandPosition (void);
void updateflightSpeed (void);
void updateArrivalReturnSpeed (void);
void updateAltitude (void);
void checkBatteryLevel (void);
void smartRTLCleanUp (bool flying); // cleans up after successfull smart RTL
void enableDisableLowBatteryHandling (QVariant enable);
void reverseChangedHandler ();
void _initSmartRTL ();
void _executeSmartRTL ();
bool _fetchContainerData();
bool _calcNextPhase(void);
void _updateWaypointPath (void);
void _updateCurrentPath (void);
void _updateNextWaypoint (void);
void _recalcCurrentPhase (void);
bool _setTakeoffLandPosition (void);
void _updateflightSpeed (void);
void _updateArrivalReturnSpeed (void);
void _updateAltitude (void);
void _checkBatteryLevel (void);
void _eventTimerHandler (void);
void _smartRTLCleanUp (bool flying); // cleans up after successfull smart RTL
void _enableDisableLowBatteryHandling (QVariant enable);
void _reverseChangedHandler ();
void _initSmartRTL ();
void _executeSmartRTL ();
void _setSnakeConnectionStatus (SnakeConnectionStatus status);
void _setSnakeCalcInProgress (bool inProgress);
bool _verifyScenarioDefined (void);
bool _verifyScenarioDefinedWithErrorMessage (void);
void _snakeResultsReady (const WorkerResult_t &r);
private:
......@@ -206,7 +244,6 @@ private:
void _loadCurrentMissionItemsFromBuffer();
void _saveCurrentMissionItemsToBuffer();
private:
PlanMasterController *_masterController;
MissionController *_missionController;
QString _currentFile; // file for saveing
......@@ -238,6 +275,7 @@ private:
SettingsFact _arrivalReturnSpeed; // arrival and return path speed
SettingsFact _altitude; // mission altitude
SettingsFact _reverse; // Reverses the phase direction. Phases go from high to low waypoint numbers, if true.
SettingsFact _enableSnake; // Enable Snake (see snake.h)
int _endWaypointIndex; // index of the mission item stored in _missionItems defining the last element
// (which is not part of the return path) of _currentMissionItem
......@@ -253,7 +291,7 @@ private:
double _phaseDistanceBuffer; // buffer for storing _phaseDistance when doing smart RTL
double _phaseDurationBuffer; // buffer for storing _phaseDuration when doing smart RTL
QTimer _checkBatteryTimer;
QTimer _eventTimer;
QTimer _smartRTLAttemptTimer;
SRTL_Reason _srtlReason;
......@@ -261,15 +299,25 @@ private:
bool _lowBatteryHandlingTriggered;
bool _executingSmartRTL;
Scenario _snakeScenario;
FlightPlan _snakeFlightPlan;
// Snake
SnakeConnectionStatus _snakeConnectionStatus;
bool _snakeCalcInProgress;
bool _snakeRecalcNecessary;
bool _scenarioDefinedBool;
SnakeWorker _snakeWorker;
Scenario _scenario;
SettingsFact _snakeTileWidth;
SettingsFact _snakeTileHeight;
SettingsFact _snakeMinTileArea;
SettingsFact _snakeLineDistance;
SettingsFact _snakeMinTransectLength;
};
/*
* The following explains the structure of
* _missionController.visualItems(). The indices
* are not that important and only specified for
* reasons of completeness.
* _missionController.visualItems().
*
* Index Description
* --------------------------------------------
......
#include "WimaControllerDetail.h"
#include <QGeoCoordinate>
SnakeWorker::SnakeWorker(QObject *parent) : QThread(parent)
, _lineDistance (3) // meter
, _minTransectLength (2) // meter
{
}
void SnakeWorker::setScenario(const Scenario &scenario)
{
_scenario = scenario;
}
void SnakeWorker::setProgress(const QList<qint8> &progress)
{
for (auto p : progress) {
assert(p >= -1);
assert(p <= 100);
_progress.push_back(p);
}
}
void SnakeWorker::setLineDistance(double lineDistance)
{
assert(lineDistance > 0);
_lineDistance = lineDistance;
}
void SnakeWorker::setMinTransectLength(double minTransectLength)
{
assert(minTransectLength > 0);
_minTransectLength = minTransectLength;
}
void SnakeWorker::run()
{
WorkerResult_t result{QVariantList{},
QVector<unsigned long>{},
QVector<unsigned long>{},
false,
QString{}};
// partial success
FlightPlan flightplan;
flightplan.setScenario(_scenario);
flightplan.setProgress(_progress);
// Trying to generate flight plan.
if ( !flightplan.generate(_lineDistance, _minTransectLength) ){
// error
for (auto c : flightplan.errorString){
result.errorMessage.push_back(QChar(c));
}
} else {
//success!!!
// Fill result struct.
auto waypoints = flightplan.getWaypoints();
for (auto vertex : waypoints){
result.waypoints.append(QVariant::fromValue(QGeoCoordinate(vertex[0], vertex[1], 0)));
}
auto arrivalPathIdx = flightplan.getArrivalPathIdx();
for (auto idx : arrivalPathIdx){
result.arrivalPathIdx.append(idx);
}
auto returnPathIdx = flightplan.getReturnPathIdx();
for (auto idx : returnPathIdx){
result.returnPathIdx.append(idx);
}
}
emit resultReady(result);
}
#pragma once
#include <QObject>
#include <QVariant>
#include <QThread>
#include <QVector>
#include "snake_geometry.h"
#include "snake.h"
using namespace snake;
using namespace snake_geometry;
using namespace std;
typedef QList<QVariant> QVariantList;
typedef struct Result{
QVariantList waypoints;
QVector<unsigned long> arrivalPathIdx;
QVector<unsigned long> returnPathIdx;
bool success;
QString errorMessage;
}WorkerResult_t;
class SnakeWorker : public QThread{
Q_OBJECT
public:
SnakeWorker(QObject *parent = nullptr);
void setScenario (const Scenario &scenario);
void setProgress (const QList<qint8> &progress);
void setLineDistance (double lineDistance);
void setMinTransectLength (double minTransectLength);
signals:
void resultReady(const WorkerResult_t &result);
protected:
void run() override;
private:
Scenario _scenario;
vector<int8_t> _progress;
double _lineDistance;
double _minTransectLength;
};
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_QGCCorePlugin.cpp"
#include "EWIEGA46WW/moc_QGCOptions.cpp"
#include "EWIEGA46WW/moc_QGCSettings.cpp"
#include "EWIEGA46WW/moc_QmlComponentInfo.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_LinkConfiguration.cpp"
#include "EWIEGA46WW/moc_LinkInterface.cpp"
#include "EWIEGA46WW/moc_LinkManager.cpp"
#include "EWIEGA46WW/moc_LogReplayLink.cpp"
#include "EWIEGA46WW/moc_MAVLinkProtocol.cpp"
#include "EWIEGA46WW/moc_MavlinkMessagesTimer.cpp"
#include "EWIEGA46WW/moc_MockLink.cpp"
#include "EWIEGA46WW/moc_MockLinkFileServer.cpp"
#include "EWIEGA46WW/moc_MockLinkMissionItemHandler.cpp"
#include "EWIEGA46WW/moc_QGCFlightGearLink.cpp"
#include "EWIEGA46WW/moc_QGCHilLink.cpp"
#include "EWIEGA46WW/moc_QGCJSBSimLink.cpp"
#include "EWIEGA46WW/moc_QGCXPlaneLink.cpp"
#include "EWIEGA46WW/moc_SerialLink.cpp"
#include "EWIEGA46WW/moc_TCPLink.cpp"
#include "EWIEGA46WW/moc_UDPLink.cpp"
#include "EWIEGA46WW/moc_UdpIODevice.cpp"
#ifndef UTILITIES_H
#define UTILITIES_H
#include <assert.h>
//!
//! \brief The EventTicker class is a helper class used to determine if a certain event is ready to be executed.
//!
//! The EventTicker class is a helper class used to determine if a certain event is ready to be executed. This class supposed to be used in combination with a Timer provided by the user.
//!
class EventTicker{
public:
//!
//! \brief EventTicker Constructor used to build non initilized Object. Call \fn init() befor use.
//!
EventTicker() : _isInitialized(false) {
_isInitialized = false;
}
//!
//! \brief EventTicker Constructor used for initilization. The function \fn must not be called if this constructor is used.
//! \param timerInterval The timer interval of the timer provided by the user.
//! \param tickInterval The thick intervall (timerInterval <= tickInterval), see \fn ready().
//!
EventTicker(double timerInterval, double tickInterval) {
_isInitialized = false;
init(timerInterval, tickInterval);
}
//!
//! \brief init Used to init the EventTicker.
//! \param timerInterval The timer interval of the timer provided by the user.
//! \param tickInterval The thick intervall (timerInterval <= tickInterval), see \fn ready().
//!
void init(double timerInterval, double tickInterval){
assert(_isInitialized == false);
assert(timerInterval > 0);
assert(tickInterval >= timerInterval);
_timerInterval = timerInterval;
_tickInerval = tickInterval;
_tickCount = 0;
_isInitialized = true;
}
//!
//! \brief ready This function must be called by a user provided timer interrupt handler.
//! \return True if the event is ready to be executed, false either.
//!
//! This function must be called by a user provided timer interrupt handler. A internal counter increases with every call.
//! If timerInterval <= tickInerval*counter the counter gets reset and the function returns true. If the condition is not
//! met the function returns false.
//!
bool ready(void) {
assert(_isInitialized == true);
_tickCount++;
bool ready = _timerInterval <= _tickInerval*_tickCount;
if (ready)
_tickCount = 0;
return ready;
}
private:
double _timerInterval;
double _tickInerval;
unsigned long _tickCount;
bool _isInitialized;
};
#endif // UTILITIES_H
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_KMLFileHelper.cpp"
#include "EWIEGA46WW/moc_LogCompressor.cpp"
#include "EWIEGA46WW/moc_QGC.cpp"
#include "EWIEGA46WW/moc_QGCApplication.cpp"
#include "EWIEGA46WW/moc_QGCComboBox.cpp"
#include "EWIEGA46WW/moc_QGCDockWidget.cpp"
#include "EWIEGA46WW/moc_QGCFileDownload.cpp"
#include "EWIEGA46WW/moc_QGCLoggingCategory.cpp"
#include "EWIEGA46WW/moc_QGCMapPalette.cpp"
#include "EWIEGA46WW/moc_QGCPalette.cpp"
#include "EWIEGA46WW/moc_QGCQGeoCoordinate.cpp"
#include "EWIEGA46WW/moc_QGCQmlWidgetHolder.cpp"
#include "EWIEGA46WW/moc_QGCQuickWidget.cpp"
#include "EWIEGA46WW/moc_QGCTemporaryFile.cpp"
#include "EWIEGA46WW/moc_QGCToolbox.cpp"
#include "EWIEGA46WW/moc_SHPFileHelper.cpp"
#include "EWIEGA46WW/moc_ShapeFileHelper.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_FileDialogTest.cpp"
#include "EWIEGA46WW/moc_FileManagerTest.cpp"
#include "EWIEGA46WW/moc_FlightGearTest.cpp"
#include "EWIEGA46WW/moc_GeoTest.cpp"
#include "EWIEGA46WW/moc_LinkManagerTest.cpp"
#include "EWIEGA46WW/moc_MainWindowTest.cpp"
#include "EWIEGA46WW/moc_MavlinkLogTest.cpp"
#include "EWIEGA46WW/moc_MessageBoxTest.cpp"
#include "EWIEGA46WW/moc_MultiSignalSpy.cpp"
#include "EWIEGA46WW/moc_RadioConfigTest.cpp"
#include "EWIEGA46WW/moc_TCPLinkTest.cpp"
#include "EWIEGA46WW/moc_TCPLoopBackServer.cpp"
#include "EWIEGA46WW/moc_UnitTest.cpp"
// This file is autogenerated. Changes will be overwritten.
#include "EWIEGA46WW/moc_FileManager.cpp"
#include "EWIEGA46WW/moc_UAS.cpp"
#include "EWIEGA46WW/moc_UASInterface.cpp"
#include "EWIEGA46WW/moc_UASMessageHandler.cpp"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment