├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── setup.py ├── visilibity.cpp ├── visilibity.hpp ├── visilibity.i ├── visilibity.py └── visilibity_test.py /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | env: 4 | CIBW_BEFORE_ALL_LINUX: yum install -y http://springdale.princeton.edu/data/springdale/6/x86_64/os/Computational/swig307-3.0.7-3.sdl6.x86_64.rpm && alias swig='swig307' 5 | CIBW_BEFORE_ALL_WINDOWS: choco install swig -f -y 6 | CIBW_BEFORE_ALL_MACOS: brew install swig 7 | 8 | 9 | on: [push, pull_request] 10 | 11 | jobs: 12 | 13 | build_wheels: 14 | name: Build wheels on ${{ matrix.os }} 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | matrix: 18 | os: [ubuntu-18.04, windows-latest, macos-latest] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | 23 | - uses: actions/setup-python@v2 24 | name: Install Python 25 | with: 26 | python-version: '3.7' 27 | 28 | - name: Install cibuildwheel 29 | run: | 30 | python -m pip install cibuildwheel==1.5.5 31 | 32 | - name: Install Visual C++ 33 | if: runner.os == 'Windows' 34 | run: | 35 | choco install vcpython27 -f -y 36 | 37 | - name: Build wheels 38 | run: | 39 | python -m cibuildwheel --output-dir wheelhouse 40 | 41 | - uses: actions/upload-artifact@v2 42 | with: 43 | path: ./wheelhouse/*.whl 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # dotenv 83 | .env 84 | 85 | # virtualenv 86 | .venv 87 | venv/ 88 | ENV/ 89 | 90 | # Spyder project settings 91 | .spyderproject 92 | .spyproject 93 | 94 | # Rope project settings 95 | .ropeproject 96 | 97 | # mkdocs documentation 98 | /site 99 | 100 | # mypy 101 | .mypy_cache/ 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include visilibity.hpp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyVisiLibity 2 | Python binding of [VisiLibity 1](https://karlobermeyer.github.io/VisiLibity1/). 3 | 4 | Support both Python 2.7 and Python >= 3 5 | 6 | 7 | ## Installtion 8 | 9 | 10 | `swig` is required to build C++ extension. 11 | Check [here](https://github.com/swig/swig/wiki/Getting-Started) for the instruction. 12 | 13 | 14 | To install the Python package: 15 | 16 | `pip install visilibity` 17 | 18 | ## Run test with example 19 | 20 | After installation, it would possible to run the test example `visilibity_test.py`. 21 | 22 | Get a copy of test file from this [repository](https://github.com/tsaoyu/PyVisiLibity) and run 23 | 24 | `python visilibity_test.py` 25 | 26 | The test script is self-explanatory. If anything wrong make sure you have `matplotlib` installed and configured. 27 | 28 | ## Issue 29 | 30 | Please file me any issue related to the installtion and usage of PyVisiLibity in this repository. 31 | However any issue concerned about the core function of PyVisiLibity such as add new feature, bug report need to be raised at original VisiLibity [repository](https://github.com/karlobermeyer/VisiLibity1). 32 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # PyVisiLibity: a Python binding of VisiLibity1 3 | # Copyright (C) 2018 Yu Cao < University of Southampton> Yu.Cao at soton.ac.uk 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Lesser General Public License for more details. 14 | 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with this program. If not, see . 17 | 18 | from distutils.core import setup, Extension 19 | from distutils.command.build import build 20 | 21 | class CustomBuild(build): 22 | sub_commands = [ 23 | ('build_ext', build.has_ext_modules), 24 | ('build_py', build.has_pure_modules), 25 | ('build_clib', build.has_c_libraries), 26 | ('build_scripts', build.has_scripts), 27 | ] 28 | 29 | module = Extension('_visilibity', swig_opts = ['-c++'], 30 | sources = ['visilibity.i', 'visilibity.cpp'], 31 | headers = ['visilibity.hpp'], include = ['visilibity.hpp']) 32 | 33 | setup (name = 'VisiLibity', 34 | version = '1.0.10', 35 | cmdclass = {'build': CustomBuild}, 36 | author = 'Yu Cao', 37 | author_email = 'yu.cao@soton.ac.uk', 38 | license = 'LGPL', 39 | url = 'https://github.com/tsaoyu/PyVisiLibity', 40 | description = 'Python bindings of VisiLibity1', 41 | py_modules = ['visilibity'], 42 | ext_modules = [module]) 43 | -------------------------------------------------------------------------------- /visilibity.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * \file visilibity.hpp 3 | * \authors Karl J. Obermeyer 4 | * \date March 20, 2008 5 | * 6 | VisiLibity: A Floating-Point Visibility Algorithms Library, 7 | Copyright (C) 2008 Karl J. Obermeyer (karl.obermeyer [ at ] gmail.com) 8 | 9 | This file is part of VisiLibity. 10 | 11 | VisiLibity is free software: you can redistribute it and/or modify it under 12 | the terms of the GNU Lesser General Public License as published by the 13 | Free Software Foundation, either version 3 of the License, or (at your 14 | option) any later version. 15 | 16 | VisiLibity is distributed in the hope that it will be useful, but WITHOUT 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 18 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 19 | License for more details. 20 | 21 | You should have received a copy of the GNU Lesser General Public 22 | License along with VisiLibity. If not, see . 23 | */ 24 | 25 | /** 26 | * \mainpage 27 | *
28 | * see also the VisiLibity Project Page 29 | *
30 | * Authors: Karl J. Obermeyer 31 | *
32 | * \section developers For Developers 33 | * Coding Standards 34 | *
35 | * \section release_notes Release Notes 36 | * Current Functionality 37 | *
    38 | *
  • visibility polygons in polygonal environments with holes
  • 39 | *
  • visibility graphs
  • 40 | *
  • shortest path planning for a point
  • 41 | *
42 | */ 43 | 44 | #ifndef VISILIBITY_H 45 | #define VISILIBITY_H 46 | 47 | 48 | //Uncomment these lines when compiling under 49 | //Microsoft Visual Studio 50 | /* 51 | #include 52 | #define NAN std::numeric_limits::quiet_NaN() 53 | #define INFINITY std::numeric_limits::infinity() 54 | #define M_PI 3.141592653589793238462643 55 | #define and && 56 | #define or || 57 | */ 58 | 59 | #include //math functions in std namespace 60 | #include 61 | #include //queue and priority_queue. 62 | #include //priority queues with iteration, 63 | //integrated keys 64 | #include 65 | #include //sorting, min, max, reverse 66 | #include //rand and srand 67 | #include //Unix time 68 | #include //file I/O 69 | #include 70 | #include //C-string manipulation 71 | #include //string class 72 | #include //assertions 73 | 74 | 75 | /// VisiLibity's sole namespace 76 | namespace VisiLibity 77 | { 78 | 79 | //Fwd declaration of all classes and structs serves as index. 80 | struct Bounding_Box; 81 | class Point; 82 | class Line_Segment; 83 | class Angle; 84 | class Ray; 85 | class Polar_Point; 86 | class Polyline; 87 | class Polygon; 88 | class Environment; 89 | class Guards; 90 | class Visibility_Polygon; 91 | class Visibility_Graph; 92 | 93 | 94 | /** \brief floating-point display precision. 95 | * 96 | * This is the default precision with which floating point 97 | * numbers are displayed or written to files for classes with a 98 | * write_to_file() method. 99 | */ 100 | const int FIOS_PRECISION = 10; 101 | 102 | 103 | /** \brief get a uniform random sample from an (inclusive) interval 104 | * on the real line 105 | * 106 | * \author Karl J. Obermeyer 107 | * \param lower_bound lower bound of the real interval 108 | * \param upper_bound upper bound of the real interval 109 | * \pre \a lower_bound <= \a upper_bound 110 | * \return a random sample from a uniform probability distribution 111 | * on the real interval [\a lower_bound, \a upper_bound] 112 | * \remarks Uses the Standard Library's rand() function. rand() 113 | * should be seeded (only necessary once at the beginning of the 114 | * program) using the command 115 | * std::srand( std::time( NULL ) ); rand(); 116 | * \warning performance degrades as upper_bound - lower_bound 117 | * approaches RAND_MAX. 118 | */ 119 | double uniform_random_sample(double lower_bound, double upper_bound); 120 | 121 | 122 | /** \brief rectangle with sides parallel to the x- and y-axes 123 | * 124 | * \author Karl J. Obermeyer 125 | * Useful for enclosing other geometric objects. 126 | */ 127 | struct Bounding_Box { double x_min, x_max, y_min, y_max; }; 128 | 129 | 130 | /// Point in the plane represented by Cartesian coordinates 131 | class Point 132 | { 133 | public: 134 | //Constructors 135 | /** \brief default 136 | * 137 | * \remarks Data defaults to NAN so that checking whether the 138 | * data are numbers can be used as a precondition in functions. 139 | */ 140 | Point() : x_(NAN) , y_(NAN) { } 141 | /// costruct from raw coordinates 142 | Point(double x_temp, double y_temp) 143 | { x_=x_temp; y_=y_temp; } 144 | //Accessors 145 | /// get x coordinate 146 | double x () const { return x_; } 147 | /// get y coordinate 148 | double y () const { return y_; } 149 | /** \brief closest Point on \a line_segment_temp 150 | * 151 | * \author Karl J. Obermeyer 152 | * \pre the calling Point data are numbers 153 | * and \a line_segment_temp is nonempty 154 | * \return the Point on \a line_segment_temp which is the smallest 155 | * Euclidean distance from the calling Point 156 | */ 157 | Point projection_onto(const Line_Segment& line_segment_temp) const; 158 | /** \brief closest Point on \a ray_temp 159 | * 160 | * \author Karl J. Obermeyer 161 | * \pre the calling Point and \a ray_temp data are numbers 162 | * \return the Point on \a ray_temp which is the smallest 163 | * Euclidean distance from the calling Point 164 | */ 165 | Point projection_onto(const Ray& ray_temp) const; 166 | /** \brief closest Point on \a polyline_temp 167 | * 168 | * \pre the calling Point data are numbers and \a polyline_temp 169 | * is nonempty 170 | * \return the Point on \a polyline_temp which is the smallest 171 | * Euclidean distance from the calling Point 172 | */ 173 | Point projection_onto(const Polyline& polyline_temp) const; 174 | /** \brief closest vertex of \a polygon_temp 175 | * 176 | * \author Karl J. Obermeyer 177 | * \pre the calling Point data are numbers and \a polygon_temp 178 | * is nonempty 179 | * \return the vertex of \a polygon_temp which is the 180 | * smallest Euclidean distance from the calling Point 181 | */ 182 | Point projection_onto_vertices_of(const Polygon& polygon_temp) const; 183 | /** \brief closest vertex of \a environment_temp 184 | * 185 | * \author Karl J. Obermeyer 186 | * \pre the calling Point data are numbers and \a environment_temp 187 | * is nonempty 188 | * \return the vertex of \a environment_temp which is 189 | * the smallest Euclidean distance from the calling Point 190 | */ 191 | Point projection_onto_vertices_of(const Environment& 192 | enviroment_temp) const; 193 | /** \brief closest Point on boundary of \a polygon_temp 194 | * 195 | * \author Karl J. Obermeyer 196 | * \pre the calling Point data are numbers and \a polygon_temp 197 | * is nonempty 198 | * \return the Point on the boundary of \a polygon_temp which is the 199 | * smallest Euclidean distance from the calling Point 200 | */ 201 | Point projection_onto_boundary_of(const Polygon& polygon_temp) const; 202 | /** \brief closest Point on boundary of \a environment_temp 203 | * 204 | * \author Karl J. Obermeyer 205 | * \pre the calling Point data are numbers and \a environment_temp 206 | * is nonempty 207 | * \return the Point on the boundary of \a environment_temp which is 208 | * the smalles Euclidean distance from the calling Point 209 | */ 210 | Point projection_onto_boundary_of(const Environment& 211 | enviroment_temp) const; 212 | /** \brief true iff w/in \a epsilon of boundary of \a polygon_temp 213 | * 214 | * \author Karl J. Obermeyer 215 | * \pre the calling Point data are numbers and \a polygon_temp 216 | * is nonempty 217 | * \return true iff the calling Point is within Euclidean distance 218 | * \a epsilon of \a polygon_temp 's boundary 219 | * \remarks O(n) time complexity, where n is the number 220 | * of vertices of \a polygon_temp 221 | */ 222 | bool on_boundary_of(const Polygon& polygon_temp, 223 | double epsilon=0.0) const; 224 | /** \brief true iff w/in \a epsilon of boundary of \a environment_temp 225 | * 226 | * \author Karl J. Obermeyer 227 | * \pre the calling Point data are numbers and \a environment_temp 228 | * is nonempty 229 | * \return true iff the calling Point is within Euclidean distance 230 | * \a epsilon of \a environment_temp 's boundary 231 | * \remarks O(n) time complexity, where n is the number 232 | * of vertices of \a environment_temp 233 | */ 234 | bool on_boundary_of(const Environment& environment_temp, 235 | double epsilon=0.0) const; 236 | /** \brief true iff w/in \a epsilon of \a line_segment_temp 237 | * 238 | * \author Karl J. Obermeyer 239 | * \pre the calling Point data are numbers and \a line_segment_temp 240 | * is nonempty 241 | * \return true iff the calling Point is within distance 242 | * \a epsilon of the (closed) Line_Segment \a line_segment_temp 243 | */ 244 | bool in(const Line_Segment& line_segment_temp, 245 | double epsilon=0.0) const; 246 | /** \brief true iff w/in \a epsilon of interior but greater than 247 | * \a espilon away from endpoints of \a line_segment_temp 248 | * 249 | * \author Karl J. Obermeyer 250 | * \pre the calling Point data are numbers and \a line_segment_temp 251 | * is nonempty 252 | * \return true iff the calling Point is within distance \a 253 | * epsilon of \line_segment_temp, but distance (strictly) greater 254 | * than epsilon from \a line_segment_temp 's endpoints. 255 | */ 256 | bool in_relative_interior_of(const Line_Segment& line_segment_temp, 257 | double epsilon=0.0) const; 258 | /** \brief true iff w/in \a epsilon of \a polygon_temp 259 | * 260 | * \author Karl J. Obermeyer 261 | * 262 | * \pre the calling Point data are numbers and \a polygon_temp is 263 | * \a epsilon -simple. Test simplicity with 264 | * Polygon::is_simple(epsilon) 265 | * 266 | * \return true iff the calling Point is a Euclidean distance no greater 267 | * than \a epsilon from the (closed) Polygon (with vertices listed 268 | * either cw or ccw) \a polygon_temp. 269 | * \remarks O(n) time complexity, where n is the number of vertices 270 | * in \a polygon_temp 271 | */ 272 | bool in(const Polygon& polygon_temp, 273 | double epsilon=0.0) const; 274 | /** \brief true iff w/in \a epsilon of \a environment_temp 275 | * 276 | * \author Karl J. Obermeyer 277 | * 278 | * \pre the calling Point data are numbers and \a environment_temp 279 | * is nonempty and \a epsilon -valid. Test validity with 280 | * Enviroment::is_valid(epsilon) 281 | * 282 | * \return true iff the calling Point is a Euclidean distance no greater 283 | * than \a epsilon from the in the (closed) Environment \a environment_temp 284 | * \remarks O(n) time complexity, where n is the number of 285 | * vertices in \a environment_temp 286 | */ 287 | bool in(const Environment& environment_temp, 288 | double epsilon=0.0) const; 289 | /** \brief true iff w/in \a epsilon of some endpoint 290 | * of \a line_segment_temp 291 | * 292 | * \pre the calling Point data are numbers and \a line_segment_temp 293 | * is nonempty 294 | * \return true iff calling Point is a Euclidean distance no greater 295 | * than \a epsilon from some endpoint of \a line_segment_temp 296 | */ 297 | bool is_endpoint_of(const Line_Segment& line_segment_temp, 298 | double epsilon=0.0) const; 299 | //Mutators 300 | /// change x coordinate 301 | void set_x(double x_temp) { x_ = x_temp;} 302 | /// change y coordinate 303 | void set_y(double y_temp) { y_ = y_temp;} 304 | /** \brief relocate to closest vertex if w/in \a epsilon of some 305 | * vertex (of \a polygon_temp) 306 | * 307 | * \author Karl J. Obermeyer 308 | * \pre the calling Point data are numbers and \a polygon_temp 309 | * is nonempty 310 | * \post If the calling Point was a Euclidean distance no greater 311 | * than \a epsilon from any vertex of \a polygon_temp, then it 312 | * will be repositioned to coincide with the closest such vertex 313 | * \remarks O(n) time complexity, where n is the number of 314 | * vertices in \a polygon_temp. 315 | */ 316 | void snap_to_vertices_of(const Polygon& polygon_temp, 317 | double epsilon=0.0); 318 | /** \brief relocate to closest vertex if w/in \a epsilon of some 319 | * vertex (of \a environment_temp) 320 | * 321 | * \author Karl J. Obermeyer 322 | * \pre the calling Point data are numbers and \a environment_temp 323 | * is nonempty 324 | * \post If the calling Point was a Euclidean distance no greater 325 | * than \a epsilon from any vertex of \a environment_temp, then it 326 | * will be repositioned to coincide with the closest such vertex 327 | * \remarks O(n) time complexity, where n is the number of 328 | * vertices in \a environment_temp. 329 | */ 330 | void snap_to_vertices_of(const Environment& environment_temp, 331 | double epsilon=0.0); 332 | /** \brief relocate to closest Point on boundary if w/in \a epsilon 333 | * of the boundary (of \a polygon_temp) 334 | * 335 | * \author Karl J. Obermeyer 336 | * \pre the calling Point data are numbers and \a polygon_temp 337 | * is nonempty 338 | * \post if the calling Point was a Euclidean distance no greater 339 | * than \a epsilon from the boundary of \a polygon_temp, then it 340 | * will be repositioned to it's projection onto that boundary 341 | * \remarks O(n) time complexity, where n is the number of 342 | * vertices in \a polygon_temp. 343 | */ 344 | void snap_to_boundary_of(const Polygon& polygon_temp, 345 | double epsilon=0.0); 346 | /** \brief relocate to closest Point on boundary if w/in \a epsilon 347 | * of the boundary (of \a environment_temp) 348 | * 349 | * \author Karl J. Obermeyer 350 | * \pre the calling Point data are numbers and \a environment_temp 351 | * is nonempty 352 | * \post if the calling Point was a Euclidean distance no greater 353 | * than \a epsilon from the boundary of \a environment_temp, then it 354 | * will be repositioned to it's projection onto that boundary 355 | * \remarks O(n) time complexity, where n is the number of 356 | * vertices in \a environment_temp. 357 | */ 358 | void snap_to_boundary_of(const Environment& environment_temp, 359 | double epsilon=0.0); 360 | protected: 361 | double x_; 362 | double y_; 363 | }; 364 | 365 | 366 | /** \brief True iff Points' coordinates are identical. 367 | * 368 | * \remarks NAN==NAN returns false, so if either point has 369 | * not been assigned real number coordinates, they will not be == 370 | */ 371 | bool operator == (const Point& point1, const Point& point2); 372 | /// True iff Points' coordinates are not identical. 373 | bool operator != (const Point& point1, const Point& point2); 374 | 375 | 376 | /** \brief compare lexicographic order of points 377 | * 378 | * For Points p1 and p2, p1 < p2 iff either p1.x() < p2.x() or 379 | * p1.x()==p2.x() and p1.y() (const Point& point1, const Point& point2); 394 | /** \brief compare lexicographic order of points 395 | * 396 | * For Points p1 and p2, p1 < p2 iff either p1.x() < p2.x() or 397 | * p1.x()==p2.x() and p1.y()= (const Point& point1, const Point& point2); 403 | /** \brief compare lexicographic order of points 404 | * 405 | * For Points p1 and p2, p1 < p2 iff either p1.x() < p2.x() or 406 | * p1.x()==p2.x() and p1.y() 0 553 | * \return the first Point of the Line_Segment 554 | * \remarks If size() == 1, then both first() and second() are valid 555 | * and will return the same Point 556 | */ 557 | Point first() const; 558 | /** \brief second endpoint 559 | * 560 | * \pre size() > 0 561 | * \return the second Point of the Line_Segment 562 | * \remarks If size() == 1, then both first() and second() are valid 563 | * and will return the same Point 564 | */ 565 | Point second() const; 566 | /** \brief number of distinct endpoints 567 | * 568 | * \remarks 569 | * size 0 => empty line segment; 570 | * size 1 => degenerate (single point) line segment; 571 | * size 2 => full-fledged (bona fide) line segment 572 | */ 573 | unsigned size() const { return size_; } 574 | /** \brief midpoint 575 | * 576 | * \pre size() > 0 577 | */ 578 | Point midpoint() const; 579 | /** \brief Euclidean length 580 | * 581 | * \pre size() > 0 582 | */ 583 | double length() const; 584 | /** \brief true iff vertices in lex. order 585 | * 586 | * \pre size() > 0 587 | * \return true iff vertices are listed beginning with the vertex 588 | * which is lexicographically smallest (lowest x, then lowest y) 589 | * \remarks lex. comparison is very sensitive to perturbations if 590 | * two Points nearly define a line parallel to one of the axes 591 | */ 592 | bool is_in_standard_form() const; 593 | //Mutators 594 | /// assignment operator 595 | Line_Segment& operator = (const Line_Segment& line_segment_temp); 596 | /** \brief set first endpoint 597 | * 598 | * \remarks if \a point_temp is w/in a distance \a epsilon of an existing 599 | * endpoint, the coordinates of \a point_temp are used and size is set to 600 | * 1 as appropriate 601 | */ 602 | void set_first(const Point& point_temp, double epsilon=0.0); 603 | /** \brief set second endpoint 604 | * 605 | * \remarks if \a point_temp is w/in a distance \a epsilon of an existing 606 | * endpoint, the coordinates of \a point_temp are used and size is set to 607 | * 1 as appropriate 608 | */ 609 | void set_second(const Point& point_temp, double epsilon=0.0); 610 | /** \brief reverse order of endpoints 611 | * 612 | * \post order of endpoints is reversed. 613 | */ 614 | void reverse(); 615 | /** \brief enforce that lex. smallest endpoint first 616 | * 617 | * \post the lexicographically smallest endpoint (lowest x, then lowest y) 618 | * is first 619 | * \remarks lex. comparison is very sensitive to perturbations if 620 | * two Points nearly define a line parallel to one of the axes 621 | */ 622 | void enforce_standard_form(); 623 | /// erase both endpoints and set line segment empty (size 0) 624 | void clear(); 625 | /// destructor 626 | virtual ~Line_Segment(); 627 | protected: 628 | //Pointer to dynamic array of endpoints. 629 | Point *endpoints_; 630 | //See size() comments. 631 | unsigned size_; 632 | }; 633 | 634 | 635 | /** \brief true iff endpoint coordinates are exactly equal, but 636 | * false if either Line_Segment has size 0 637 | * 638 | * \remarks respects ordering of vertices, i.e., even if the line segments 639 | * overlap exactly, they are not considered == unless the orientations are 640 | * the same 641 | */ 642 | bool operator == (const Line_Segment& line_segment1, 643 | const Line_Segment& line_segment2); 644 | /// true iff endpoint coordinates are not == 645 | bool operator != (const Line_Segment& line_segment1, 646 | const Line_Segment& line_segment2); 647 | 648 | 649 | /** \brief true iff line segments' endpoints match up w/in a (closed) 650 | * \a epsilon ball of each other, but false if either 651 | * Line_Segment has size 0 652 | * 653 | * \author Karl J. Obermeyer 654 | * \remarks this function will return true even if it has to flip 655 | * the orientation of one of the segments to get the vertices to 656 | * match up 657 | */ 658 | bool equivalent(Line_Segment line_segment1, 659 | Line_Segment line_segment2, double epsilon=0); 660 | 661 | 662 | /** \brief Euclidean distance between Line_Segments 663 | * 664 | * \author Karl J. Obermeyer 665 | * \pre \a line_segment1.size() > 0 and \a line_segment2.size() > 0 666 | */ 667 | double distance(const Line_Segment& line_segment1, 668 | const Line_Segment& line_segment2); 669 | 670 | 671 | /** \brief Euclidean distance between a Line_Segment and the 672 | * boundary of a Polygon 673 | * 674 | * \author Karl J. Obermeyer 675 | * \pre \a line_segment.size() > 0 and \a polygon.n() > 0 676 | */ 677 | double boundary_distance(const Line_Segment& line_segment, 678 | const Polygon& polygon); 679 | 680 | 681 | /** \brief Euclidean distance between a Line_Segment and the 682 | * boundary of a Polygon 683 | * 684 | * \author Karl J. Obermeyer 685 | * \pre \a line_segment.size() > 0 and \a polygon.n() > 0 686 | */ 687 | double boundary_distance(const Polygon& polygon, 688 | const Line_Segment& line_segment); 689 | 690 | 691 | /** \brief true iff the Euclidean distance between Line_Segments is 692 | * no greater than \a epsilon, false if either line segment 693 | * has size 0 694 | * 695 | * \author Karl J. Obermeyer 696 | */ 697 | bool intersect(const Line_Segment& line_segment1, 698 | const Line_Segment& line_segment2, 699 | double epsilon=0.0); 700 | 701 | 702 | /** \brief true iff line segments intersect properly w/in epsilon, 703 | * false if either line segment has size 0 704 | * 705 | * \author Karl J. Obermeyer 706 | * \return true iff Line_Segments intersect exactly at a single 707 | * point in their relative interiors. For robustness, here the 708 | * relative interior of a Line_Segment is consider to be any Point 709 | * in the Line_Segment which is a distance greater than \a epsilon 710 | * from both endpoints. 711 | */ 712 | bool intersect_proper(const Line_Segment& line_segment1, 713 | const Line_Segment& line_segment2, 714 | double epsilon=0.0); 715 | 716 | 717 | /** \brief intersection of Line_Segments 718 | * 719 | * \author Karl J. Obermeyer 720 | * \return a Line_Segment of size 0, 1, or 2 721 | * \remarks size 0 results if the distance (or at least the 722 | * floating-point computed distance) between line_segment1 and 723 | * line_segment2 is (strictly) greater than epsilon. size 1 results 724 | * if the segments intersect poperly, form a T intersection, or -- 725 | * intersection. size 2 results when two or more endpoints are a 726 | * Euclidean distance no greater than \a epsilon from the opposite 727 | * segment, and the overlap of the segments has a length greater 728 | * than \a epsilon. 729 | */ 730 | Line_Segment intersection(const Line_Segment& line_segment1, 731 | const Line_Segment& line_segment2, 732 | double epsilon=0.0); 733 | 734 | 735 | /// print a Line_Segment 736 | std::ostream& operator << (std::ostream& outs, 737 | const Line_Segment& line_segment_temp); 738 | 739 | 740 | /** \brief angle in radians represented by a value in 741 | * the interval [0,2*M_PI] 742 | * 743 | * \remarks the intended interpretation is that angles 0 and 2*M_PI 744 | * correspond to the positive x-axis of the coordinate system 745 | */ 746 | class Angle 747 | { 748 | public: 749 | //Constructors 750 | /** \brief default 751 | * 752 | * \remarks data defaults to NAN so that checking whether the 753 | * data are numbers can be used as a precondition in functions 754 | */ 755 | Angle() : angle_radians_(NAN) { } 756 | /// construct from real value, mod into interval [0, 2*M_PI) 757 | Angle(double data_temp); 758 | /** \brief construct using 4 quadrant inverse tangent into [0, 2*M_PI), 759 | * where 0 points along the x-axis 760 | */ 761 | Angle(double rise_temp, double run_temp); 762 | //Accessors 763 | /// get radians 764 | double get() const { return angle_radians_; } 765 | //Mutators 766 | /// set angle, mod into interval [0, 2*PI) 767 | void set(double data_temp); 768 | /** \brief set angle data to 2*M_PI 769 | * 770 | * \remarks sometimes it is necessary to set the angle value to 771 | * 2*M_PI instead of 0, so that the lex. inequalities behave 772 | * appropriately during a radial line sweep 773 | */ 774 | void set_to_2pi() { angle_radians_=2*M_PI; } 775 | /// set to new random angle in [0, 2*M_PI) 776 | void randomize(); 777 | private: 778 | double angle_radians_; 779 | }; 780 | 781 | 782 | /// compare angle radians 783 | bool operator == (const Angle& angle1, const Angle& angle2); 784 | /// compare angle radians 785 | bool operator != (const Angle& angle1, const Angle& angle2); 786 | 787 | 788 | /// compare angle radians 789 | bool operator > (const Angle& angle1, const Angle& angle2); 790 | /// compare angle radians 791 | bool operator < (const Angle& angle1, const Angle& angle2); 792 | /// compare angle radians 793 | bool operator >= (const Angle& angle1, const Angle& angle2); 794 | /// compare angle radians 795 | bool operator <= (const Angle& angle1, const Angle& angle2); 796 | 797 | 798 | /// add angles' radians and mod into [0, 2*M_PI) 799 | Angle operator + (const Angle& angle1, const Angle& angle2); 800 | /// subtract angles' radians and mod into [0, 2*M_PI) 801 | Angle operator - (const Angle& angle1, const Angle& angle2); 802 | 803 | 804 | /** \brief geodesic distance in radians between Angles 805 | * 806 | * \author Karl J. Obermeyer 807 | * \pre \a angle1 and \a angle2 data are numbers 808 | */ 809 | double geodesic_distance(const Angle& angle1, const Angle& angle2); 810 | 811 | 812 | /** \brief 1.0 => geodesic path from angle1 to angle2 813 | * is couterclockwise, -1.0 => clockwise 814 | * 815 | * \author Karl J. Obermeyer 816 | * \pre \a angle1 and \a angle2 data are numbers 817 | */ 818 | double geodesic_direction(const Angle& angle1, const Angle& angle2); 819 | 820 | 821 | /// print Angle 822 | std::ostream& operator << (std::ostream& outs, const Angle& angle_temp); 823 | 824 | 825 | /** \brief Point in the plane packaged together with polar 826 | * coordinates w.r.t. specified origin 827 | * 828 | * The origin of the polar coordinate system is stored with the 829 | * Polar_Point (in \a polar_origin_) and bearing is measured ccw from the 830 | * positive x-axis. 831 | * \remarks used, e.g., for radial line sweeps 832 | */ 833 | class Polar_Point : public Point 834 | { 835 | public: 836 | //Constructors 837 | /** \brief default 838 | * 839 | * \remarks Data defaults to NAN so that checking whether the 840 | * data are numbers can be used as a precondition in functions. 841 | */ 842 | Polar_Point() : Point(), range_(NAN), bearing_(NAN) { } 843 | /** \brief construct from (Cartesian) Points 844 | * 845 | * \pre member data of \a polar_origin_temp and \a point_temp have 846 | * been assigned (numbers) 847 | * \param polar_origin_temp the origin of the polar coordinate system 848 | * \param point_temp the point to be represented 849 | * \remarks if polar_origin_temp == point_temp, the default 850 | * bearing is Angle(0.0) 851 | */ 852 | Polar_Point(const Point& polar_origin_temp, 853 | const Point& point_temp, 854 | double epsilon=0.0); 855 | //Accessors 856 | /** \brief origin of the polar coordinate system in which the point is 857 | * represented 858 | */ 859 | Point polar_origin() const { return polar_origin_; } 860 | /// Euclidean distance from the point represented to the origin of 861 | /// the polar coordinate system 862 | double range() const { return range_; } 863 | /// bearing from polar origin w.r.t. direction parallel to x-axis 864 | Angle bearing() const { return bearing_; } 865 | //Mutators 866 | /** \brief set the origin of the polar coordinate system 867 | * 868 | * \remarks x and y held constant, bearing and range modified 869 | * accordingly 870 | */ 871 | void set_polar_origin(const Point& polar_origin_temp); 872 | /** \brief set x 873 | * 874 | * \remarks polar_origin held constant, bearing and range modified 875 | * accordingly 876 | */ 877 | void set_x(double x_temp); 878 | /** \brief set y 879 | * 880 | * \remarks polar_origin held constant, bearing and range modified 881 | * accordingly 882 | */ 883 | void set_y(double y_temp); 884 | /** \brief set range 885 | * 886 | * \remarks polar_origin held constant, x and y modified 887 | * accordingly 888 | */ 889 | void set_range(double range_temp); 890 | /** \brief set bearing 891 | * 892 | * \remarks polar_origin and range held constant, x and y modified 893 | * accordingly 894 | */ 895 | void set_bearing(const Angle& bearing_temp); 896 | /** \brief set bearing Angle data to 2*M_PI 897 | * 898 | * \remarks Special function for use in computations involving a 899 | * radial line sweep; sometimes it is necessary to set the angle 900 | * value to 2*PI instead of 0, so that the lex. inequalities 901 | * behave appropriately 902 | */ 903 | void set_bearing_to_2pi() { bearing_.set_to_2pi(); } 904 | protected: 905 | //Origin of the polar coordinate system in world coordinates. 906 | Point polar_origin_; 907 | //Polar coordinates where radius always positive, and angle 908 | //measured ccw from the world coordinate system's x-axis. 909 | double range_; 910 | Angle bearing_; 911 | }; 912 | 913 | 914 | /** \brief compare member data 915 | * 916 | * \remarks returns false if any member data are NaN 917 | */ 918 | bool operator == (const Polar_Point& polar_point1, 919 | const Polar_Point& polar_point2); 920 | bool operator != (const Polar_Point& polar_point1, 921 | const Polar_Point& polar_point2); 922 | 923 | 924 | /** \brief compare according to polar lexicographic order 925 | * (smaller bearing, then smaller range) 926 | * 927 | * false if any member data have not been assigned (numbers) 928 | * \remarks lex. comparison is very sensitive to perturbations if 929 | * two Points nearly define a radial line 930 | */ 931 | bool operator > (const Polar_Point& polar_point1, 932 | const Polar_Point& polar_point2); 933 | /** \brief compare according to polar lexicographic order 934 | * (smaller bearing, then smaller range) 935 | * 936 | * false if any member data have not been assigned (numbers) 937 | * \remarks lex. comparison is very sensitive to perturbations if 938 | * two Points nearly define a radial line 939 | */ 940 | bool operator < (const Polar_Point& polar_point1, 941 | const Polar_Point& polar_point2); 942 | /** \brief compare according to polar lexicographic order 943 | * (smaller bearing, then smaller range) 944 | * 945 | * false if any member data have not been assigned (numbers) 946 | * \remarks lex. comparison is very sensitive to perturbations if 947 | * two Points nearly define a radial line 948 | */ 949 | bool operator >= (const Polar_Point& polar_point1, 950 | const Polar_Point& polar_point2); 951 | /** \brief compare according to polar lexicographic order 952 | * (smaller bearing, then smaller range) 953 | * 954 | * false if any member data have not been assigned (numbers) 955 | * \remarks lex. comparison is very sensitive to perturbations if 956 | * two Points nearly define a radial line 957 | */ 958 | bool operator <= (const Polar_Point& polar_point1, 959 | const Polar_Point& polar_point2); 960 | 961 | 962 | /// print Polar_Point 963 | std::ostream& operator << (std::ostream& outs, 964 | const Polar_Point& polar_point_temp); 965 | 966 | 967 | /// ray in the plane represented by base Point and bearing Angle 968 | class Ray 969 | { 970 | public: 971 | //Constructors 972 | /** \brief default 973 | * 974 | * \remarks data defaults to NAN so that checking whether the data 975 | * are numbers can be used as a precondition in functions 976 | */ 977 | Ray() { } 978 | /// construct ray emanating from \a base_point_temp in the direction 979 | /// \a bearing_temp 980 | Ray(Point base_point_temp, Angle bearing_temp) : 981 | base_point_(base_point_temp) , bearing_(bearing_temp) {} 982 | /// construct ray emanating from \a base_point_temp towards 983 | /// \a bearing_point 984 | Ray(Point base_point_temp, Point bearing_point); 985 | //Accessors 986 | /// get base point 987 | Point base_point() const { return base_point_; } 988 | /// get bearing 989 | Angle bearing() const { return bearing_; } 990 | //Mutators 991 | /// set base point 992 | void set_base_point(const Point& point_temp) 993 | { base_point_ = point_temp; } 994 | /// set bearing 995 | void set_bearing(const Angle& angle_temp) 996 | { bearing_ = angle_temp; } 997 | private: 998 | Point base_point_; 999 | Angle bearing_; 1000 | }; 1001 | 1002 | 1003 | /** \brief compare member data 1004 | * 1005 | * \remarks returns false if any member data are NaN 1006 | */ 1007 | bool operator == (const Ray& ray1, 1008 | const Ray& ray2); 1009 | /** \brief compare member data 1010 | * 1011 | * \remarks negation of == 1012 | */ 1013 | bool operator != (const Ray& ray1, 1014 | const Ray& ray2); 1015 | 1016 | 1017 | /** \brief compute the intersection of a Line_Segment with a Ray 1018 | * 1019 | * \author Karl J. Obermeyer 1020 | * \pre member data of \a ray_temp has been assigned (numbers) and 1021 | * \a line_segment_temp has size greater than 0 1022 | * \remarks as a convention, if the intersection has positive 1023 | * length, the Line_Segment returned has the first point closest to 1024 | * the Ray's base point 1025 | */ 1026 | Line_Segment intersection(const Ray ray_temp, 1027 | const Line_Segment& line_segment_temp, 1028 | double epsilon=0.0); 1029 | /** \brief compute the intersection of a Line_Segment with a Ray 1030 | * 1031 | * \author Karl J. Obermeyer 1032 | * \pre member data of \a ray_temp has been assigned (numbers) and 1033 | * \a line_segment_temp has size greater than 0 1034 | * \remarks as a convention, if the intersection has positive 1035 | * length, the Line_Segment returned has the first point closest to 1036 | * the Ray's base point 1037 | */ 1038 | Line_Segment intersection(const Line_Segment& line_segment_temp, 1039 | const Ray& ray_temp, 1040 | double epsilon=0.0); 1041 | 1042 | 1043 | ///oriented polyline in the plane represented by list of vertices 1044 | class Polyline 1045 | { 1046 | public: 1047 | friend class Point; 1048 | //Constructors 1049 | /// default to empty 1050 | Polyline() { } 1051 | /// construct from vector of vertices 1052 | Polyline(const std::vector& vertices_temp) 1053 | { vertices_ = vertices_temp; } 1054 | //Accessors 1055 | /** \brief raw access 1056 | * 1057 | * \remarks for efficiency, no bounds checks; usually trying to 1058 | * access out of bounds causes a bus error 1059 | */ 1060 | Point operator [] (unsigned i) const 1061 | { return vertices_[i]; } 1062 | /// vertex count 1063 | unsigned size() const 1064 | { return vertices_.size(); } 1065 | /// Euclidean length of the Polyline 1066 | double length() const; 1067 | /** \brief Euclidean diameter 1068 | * 1069 | * \pre Polyline has greater than 0 vertices 1070 | * \return the maximum Euclidean distance between all pairs of 1071 | * vertices 1072 | * \remarks time complexity O(n^2), where n is the number of 1073 | * vertices representing the Polyline 1074 | */ 1075 | double diameter() const; 1076 | //a box which fits snugly around the Polyline 1077 | Bounding_Box bbox() const; 1078 | //Mutators 1079 | /** \brief raw access 1080 | * 1081 | * \remarks for efficiency, no bounds checks; usually trying to 1082 | * access out of bounds causes a bus error 1083 | */ 1084 | Point& operator [] (unsigned i) 1085 | { return vertices_[i]; } 1086 | /// erase all points 1087 | void clear() 1088 | { vertices_.clear(); } 1089 | /// add a vertex to the back (end) of the list 1090 | void push_back(const Point& point_temp) 1091 | { vertices_.push_back(point_temp); } 1092 | /// delete a vertex to the back (end) of the list 1093 | void pop_back() 1094 | { vertices_.pop_back(); } 1095 | /// reset the whole list of vertices at once 1096 | void set_vertices(const std::vector& vertices_temp) 1097 | { vertices_ = vertices_temp; } 1098 | /** \brief eliminates vertices which are (\a epsilon) - colinear 1099 | * with their respective neighbors 1100 | * 1101 | * \author Karl J. Obermeyer 1102 | * \post the Euclidean distance between each vertex and the line 1103 | * segment connecting its neighbors is at least \a epsilon 1104 | * \remarks time complexity O(n), where n is the number of 1105 | * vertices representing the Polyline. 1106 | */ 1107 | void eliminate_redundant_vertices(double epsilon=0.0); 1108 | //Reduce number of vertices in representation... 1109 | //void smooth(double epsilon); 1110 | /// reverse order of vertices 1111 | void reverse(); 1112 | /// append the points from another polyline 1113 | std::vector path(); 1114 | /// show all vertices of the polyline 1115 | void append( const Polyline& polyline ); 1116 | private: 1117 | std::vector vertices_; 1118 | }; 1119 | 1120 | 1121 | //print Polyline 1122 | std::ostream& operator << (std::ostream& outs, 1123 | const Polyline& polyline_temp); 1124 | 1125 | 1126 | /** \brief simple polygon in the plane represented by list of vertices 1127 | * 1128 | * Simple here means non-self-intersecting. More precisely, edges 1129 | * should not (i) intersect with an edge not adjacent to it, nor 1130 | * (ii) intersect at more than one Point with an adjacent edge. 1131 | * \remarks vertices may be listed cw or ccw 1132 | */ 1133 | class Polygon 1134 | { 1135 | public: 1136 | friend class Point; 1137 | //Constructors 1138 | ///default to empty 1139 | Polygon() { } 1140 | /** \brief construct from *.polygon file 1141 | * 1142 | * \author Karl J. Obermeyer 1143 | * \remarks for efficiency, simplicity check not called here 1144 | */ 1145 | Polygon(const std::string& filename); 1146 | /** \brief construct from vector of vertices 1147 | * 1148 | * \remarks for efficiency, simplicity check not called here 1149 | */ 1150 | Polygon(const std::vector& vertices_temp); 1151 | /** \brief construct triangle from 3 Points 1152 | * 1153 | * \remarks for efficiency, simplicity check not called here 1154 | */ 1155 | Polygon(const Point& point0, const Point& point1, const Point& point2); 1156 | //Accessors 1157 | /** \brief access with automatic wrap-around in forward direction 1158 | * 1159 | * \remarks For efficiency, no bounds check; usually trying to 1160 | * access out of bounds causes a bus error 1161 | */ 1162 | const Point& operator [] (unsigned i) const 1163 | { return vertices_[i % vertices_.size()]; } 1164 | /** \brief vertex count 1165 | * 1166 | * \remarks O(1) time complexity 1167 | */ 1168 | unsigned n() const { return vertices_.size(); } 1169 | /** \brief reflex vertex count (nonconvex vertices) 1170 | * 1171 | * \author Karl J. Obermeyer 1172 | * \remarks Works regardless of polygon orientation (ccw vs cw), 1173 | * but assumes no redundant vertices. Time complexity O(n), where 1174 | * n is the number of vertices representing the Polygon 1175 | */ 1176 | unsigned r() const; 1177 | /** \brief true iff Polygon is (\a epsilon) simple 1178 | * 1179 | * \author Karl J. Obermeyer 1180 | * 1181 | * \remarks A Polygon is considered \a epsilon -simple iff (i) the 1182 | * Euclidean distance between nonadjacent edges is no greater than 1183 | * \a epsilon, (ii) adjacent edges intersect only at their single 1184 | * shared Point, (iii) and it has at least 3 vertices. One 1185 | * consequence of these conditions is that there can be no 1186 | * redundant vertices. 1187 | */ 1188 | bool is_simple(double epsilon=0.0) const; 1189 | /** \brief true iff lexicographically smallest vertex is first in 1190 | * the list of vertices representing the Polygon 1191 | * 1192 | * \author Karl J. Obermeyer 1193 | * \remarks lex. comparison is very sensitive to perturbations if 1194 | * two Points nearly define a line parallel to one of the axes 1195 | */ 1196 | bool is_in_standard_form() const; 1197 | /// perimeter length 1198 | double boundary_length() const; 1199 | /** oriented area of the Polygon 1200 | * 1201 | * \author Karl J. Obermeyer 1202 | * \pre Polygon is simple, but for efficiency simplicity is not asserted. 1203 | * area > 0 => vertices listed ccw, 1204 | * area < 0 => cw 1205 | * \remarks O(n) time complexity, where n is the number 1206 | * of vertices representing the Polygon 1207 | */ 1208 | double area() const; 1209 | /** \brief Polygon's centroid (center of mass) 1210 | * 1211 | * \author Karl J. Obermeyer 1212 | * \pre Polygon has greater than 0 vertices and is simple, 1213 | * but for efficiency simplicity is not asserted 1214 | */ 1215 | Point centroid() const; 1216 | /** \brief Euclidean diameter 1217 | * 1218 | * \pre Polygon has greater than 0 vertices 1219 | * \return maximum Euclidean distance between all pairs of 1220 | * vertices 1221 | * \remarks time complexity O(n^2), where n is the number of 1222 | * vertices representing the Polygon 1223 | */ 1224 | double diameter() const; 1225 | /** \brief box which fits snugly around the Polygon 1226 | * 1227 | * \author Karl J. Obermeyer 1228 | * \pre Polygon has greater than 0 vertices 1229 | */ 1230 | Bounding_Box bbox() const; 1231 | // Returns a vector of n pts randomly situated in the polygon. 1232 | std::vector random_points(const unsigned& count, 1233 | double epsilon=0.0) const; 1234 | /** \brief write list of vertices to *.polygon file 1235 | * 1236 | * \author Karl J. Obermeyer 1237 | * Uses intuitive human and computer readable decimal format with 1238 | * display precision \a fios_precision_temp. 1239 | * \pre \a fios_precision_temp >=1 1240 | */ 1241 | void write_to_file(const std::string& filename, 1242 | int fios_precision_temp=FIOS_PRECISION); 1243 | //Mutators 1244 | /** \brief access with automatic wrap-around in forward direction 1245 | * 1246 | * \remarks for efficiency, no bounds check; usually trying to 1247 | * access out of bounds causes a bus error 1248 | */ 1249 | Point& operator [] (unsigned i) { return vertices_[i % vertices_.size()]; } 1250 | /// set vertices using STL vector of Points 1251 | void set_vertices(const std::vector& vertices_temp) 1252 | { vertices_ = vertices_temp; } 1253 | /// push a Point onto the back of the vertex list 1254 | void push_back(const Point& vertex_temp ) 1255 | { vertices_.push_back( vertex_temp ); } 1256 | /// erase all vertices 1257 | void clear() 1258 | { vertices_.clear(); } 1259 | /** \brief enforces that the lexicographically smallest vertex is first 1260 | * in the list of vertices representing the Polygon 1261 | * 1262 | * \author Karl J. Obermeyer 1263 | * \remarks O(n) time complexity, where n is the number of 1264 | * vertices representing the Polygon. Lex. comparison is very 1265 | * sensitive to perturbations if two Points nearly define a line 1266 | * parallel to one of the axes 1267 | */ 1268 | void enforce_standard_form(); 1269 | /** \brief eliminates vertices which are (\a epsilon) - colinear 1270 | * with their respective neighbors 1271 | * 1272 | * \author Karl J. Obermeyer 1273 | * \post the Euclidean distance between each vertex and the line 1274 | * segment connecting its neighbors is at least \a epsilon, and the 1275 | * Polygon is in standard form 1276 | * \remarks time complexity O(n), where n is the number of 1277 | * vertices representing the the Polygon 1278 | */ 1279 | void eliminate_redundant_vertices(double epsilon=0.0); 1280 | /** \brief reverse (cyclic) order of vertices 1281 | * 1282 | * \remarks vertex first in list is held first 1283 | */ 1284 | void reverse(); 1285 | protected: 1286 | std::vector vertices_; 1287 | }; 1288 | 1289 | 1290 | /** \brief true iff vertex lists are identical, but false if either 1291 | * Polygon has size 0 1292 | * 1293 | * \remarks returns false if either Polygon has size 0 1294 | * \remarks O(n) time complexity 1295 | */ 1296 | bool operator == (Polygon polygon1, Polygon polygon2); 1297 | bool operator != (Polygon polygon1, Polygon polygon2); 1298 | /** \brief true iff the Polygon's vertices match up w/in a (closed) 1299 | * epsilon ball of each other, but false if either Polygon 1300 | * has size 0 1301 | * 1302 | * Respects number, ordering, and orientation of vertices, i.e., 1303 | * even if the (conceptual) polygons represented by two Polygons are 1304 | * identical, they are not considered \a epsilon - equivalent unless 1305 | * the number of vertices is the same, the orientations are the same 1306 | * (cw vs. ccw list), and the Points of the vertex lists match up 1307 | * within epsilon. This function does attempt to match the polygons 1308 | * for all possible cyclic permutations, hence the quadratic time 1309 | * complexity. 1310 | * \author Karl J. Obermeyer 1311 | * \remarks O(n^2) time complexity, where n is the number of 1312 | * vertices representing the polygon 1313 | */ 1314 | bool equivalent(Polygon polygon1, Polygon polygon2, 1315 | double epsilon=0.0); 1316 | 1317 | 1318 | /** \brief Euclidean distance between Polygons' boundaries 1319 | * 1320 | * \author Karl J. Obermeyer 1321 | * \pre \a polygon1 and \a polygon2 each have greater than 0 vertices 1322 | */ 1323 | double boundary_distance( const Polygon& polygon1, 1324 | const Polygon& polygon2 ); 1325 | 1326 | 1327 | //print Polygon 1328 | std::ostream& operator << (std::ostream& outs, 1329 | const Polygon& polygon_temp); 1330 | 1331 | 1332 | /** \brief environment represented by simple polygonal outer boundary 1333 | * with simple polygonal holes 1334 | * 1335 | * \remarks For methods to work correctly, the outer boundary vertices must 1336 | * be listed ccw and the hole vertices cw 1337 | */ 1338 | class Environment 1339 | { 1340 | public: 1341 | friend class Point; 1342 | //Constructors 1343 | /// default to empty 1344 | Environment() { } 1345 | /** \brief construct Environment without holes 1346 | * 1347 | * \remarks time complexity O(n), where n is the number of vertices 1348 | * representing the Environment 1349 | */ 1350 | Environment(const Polygon& polygon_temp) 1351 | { outer_boundary_=polygon_temp; update_flattened_index_key(); } 1352 | /** \brief construct Environment with holes from STL vector of Polygons 1353 | * 1354 | * the first Polygon in the vector becomes the outer boundary, 1355 | * the rest become the holes 1356 | * \remarks time complexity O(n), where n is the number of vertices 1357 | * representing the Environment 1358 | */ 1359 | Environment(const std::vector& polygons); 1360 | /** construct from *.environment file. 1361 | * 1362 | * \author Karl J. Obermeyer 1363 | * \remarks time complexity O(n), where n is the number of vertices 1364 | * representing the Environment 1365 | */ 1366 | Environment(const std::string& filename); 1367 | //Accessors 1368 | /** \brief raw access to Polygons 1369 | * 1370 | * An argument of 0 accesses the outer boundary, 1 and above 1371 | * access the holes. 1372 | * \remarks for efficiency, no bounds check; usually trying to 1373 | * access out of bounds causes a bus error 1374 | */ 1375 | const Polygon& operator [] (unsigned i) const 1376 | { if(i==0){return outer_boundary_;} else{return holes_[i-1];} } 1377 | /** \brief raw access to vertices via flattened index 1378 | * 1379 | * By flattened index is intended the label given to a vertex if 1380 | * you were to label all the vertices from 0 to n-1 (where n is 1381 | * the number of vertices representing the Environment) starting 1382 | * with the first vertex of the outer boundary and progressing in 1383 | * order through all the remaining vertices of the outer boundary 1384 | * and holes. 1385 | * 1386 | * \remarks Time complexity O(1). For efficiency, no bounds 1387 | * check; usually trying to access out of bounds causes a bus 1388 | * error. 1389 | */ 1390 | const Point& operator () (unsigned k) const; 1391 | /// hole count 1392 | unsigned h() const { return holes_.size(); } 1393 | /** \brief vertex count 1394 | * 1395 | * \remarks time complexity O(h) 1396 | */ 1397 | unsigned n() const; 1398 | /** \brief total reflex vertex count (nonconvex vertices) 1399 | * 1400 | * \author Karl J. Obermeyer 1401 | * \remarks time complexity O(n), where n is the number of 1402 | * vertices representing the Environment 1403 | */ 1404 | unsigned r() const; 1405 | /** \brief true iff lexicographically smallest vertex is first in 1406 | * each list of vertices representing a Polygon of the 1407 | * Environment 1408 | * 1409 | * \author Karl J. Obermeyer 1410 | * \remarks lex. comparison is very sensitive to perturbations if 1411 | * two Points nearly define a line parallel to one of the axes 1412 | */ 1413 | bool is_in_standard_form() const; 1414 | /** \brief true iff \a epsilon -valid 1415 | * 1416 | * \a epsilon -valid means (i) the outer boundary and holes are 1417 | * pairwise \a epsilon -disjoint (no two features should come 1418 | * within \a epsilon of each other) simple polygons, (ii) outer 1419 | * boundary is oriented ccw, and (iii) holes are oriented cw. 1420 | * 1421 | * \author Karl J. Obermeyer 1422 | * 1423 | * \pre Environment has greater than 2 vertices 1424 | * (otherwise it can't even have nonzero area) 1425 | * \remarks time complexity O(h^2*n^2), where h is the number of 1426 | * holes and n is the number of vertices representing the 1427 | * Environment 1428 | */ 1429 | bool is_valid(double epsilon=0.0) const; 1430 | /** \brief sum of perimeter lengths of outer boundary and holes 1431 | * 1432 | * \author Karl J. Obermeyer 1433 | * \remarks O(n) time complexity, where n is the number of 1434 | * vertices representing the Environment 1435 | */ 1436 | double boundary_length() const; 1437 | /** \brief (obstacle/hole free) area of the Environment 1438 | * 1439 | * \author Karl J. Obermeyer 1440 | * \remarks O(n) time complexity, where n is the number of 1441 | * vertices representing the Environment 1442 | */ 1443 | double area() const; 1444 | /** \brief Euclidean diameter 1445 | * 1446 | * \author Karl J. Obermeyer 1447 | * \pre Environment has greater than 0 vertices 1448 | * \return maximum Euclidean distance between all pairs of 1449 | * vertices 1450 | * \remarks time complexity O(n^2), where n is the number of 1451 | * vertices representing the Environment 1452 | */ 1453 | double diameter() const { return outer_boundary_.diameter(); } 1454 | /** \brief box which fits snugly around the Environment 1455 | * 1456 | * \author Karl J. Obermeyer 1457 | * \pre Environment has greater than 0 vertices 1458 | */ 1459 | Bounding_Box bbox() const { return outer_boundary_.bbox(); } 1460 | /** \brief get STL vector of \a count Points randomly situated 1461 | * within \a epsilon of the Environment 1462 | * 1463 | * \author Karl J. Obermeyer 1464 | * \pre the Environment has positive area 1465 | */ 1466 | std::vector random_points(const unsigned& count, 1467 | double epsilon=0.0) const; 1468 | /** \brief compute a shortest path between 2 Points 1469 | * 1470 | * Uses the classical visibility graph method as described, e.g., 1471 | * in ``Robot Motion Planning" (Ch. 4 Sec. 1) by J.C. Latombe. 1472 | * Specifically, an A* search is performed on the visibility graph 1473 | * using the Euclidean distance as the heuristic function. 1474 | * 1475 | * \author Karl J. Obermeyer 1476 | * 1477 | * \pre \a start and \a finish must be in the environment. 1478 | * Environment must be \a epsilon -valid. Test with 1479 | * Environment::is_valid(epsilon). 1480 | * 1481 | * \remarks If multiple shortest path queries are made for the 1482 | * same Envrionment, it is better to precompute the 1483 | * Visibility_Graph. For a precomputed Visibility_Graph, the time 1484 | * complexity of a shortest_path() query is O(n^2), where n is the 1485 | * number of vertices representing the Environment. 1486 | * 1487 | * \todo return not just one, but all shortest paths (w/in 1488 | * epsilon), e.g., returning a std::vector) 1489 | */ 1490 | Polyline shortest_path(const Point& start, 1491 | const Point& finish, 1492 | const Visibility_Graph& visibility_graph, 1493 | double epsilon=0.0); 1494 | /** \brief compute shortest path between 2 Points 1495 | * 1496 | * \author Karl J. Obermeyer 1497 | * 1498 | * \pre \a start and \a finish must be in the environment. 1499 | * Environment must be \a epsilon -valid. Test with 1500 | * Environment::is_valid(epsilon). 1501 | * 1502 | * \remarks For single shortest path query, visibility graph is 1503 | * not precomputed. Time complexity O(n^3), where n is the number 1504 | * of vertices representing the Environment. 1505 | */ 1506 | Polyline shortest_path(const Point& start, 1507 | const Point& finish, 1508 | double epsilon=0.0); 1509 | /** \brief compute the faces (partition cells) of an arrangement 1510 | * of Line_Segments inside the Environment 1511 | * 1512 | * \author Karl J. Obermeyer 1513 | * \todo finish this 1514 | */ 1515 | std::vector compute_partition_cells( std::vector 1516 | partition_inducing_segments, 1517 | double epsilon=0.0 ) 1518 | { 1519 | std::vector cells; 1520 | return cells; 1521 | } 1522 | /** \brief write lists of vertices to *.environment file 1523 | * 1524 | * uses intuitive human and computer readable decimal format with 1525 | * display precision \a fios_precision_temp 1526 | * \author Karl J. Obermeyer 1527 | * \pre \a fios_precision_temp >=1 1528 | */ 1529 | void write_to_file(const std::string& filename, 1530 | int fios_precision_temp=FIOS_PRECISION); 1531 | //Mutators 1532 | /** \brief raw access to Polygons 1533 | * 1534 | * An argument of 0 accesses the outer boundary, 1 and above 1535 | * access the holes. 1536 | * \author Karl J. Obermeyer 1537 | * \remarks for efficiency, no bounds check; usually trying to 1538 | * access out of bounds causes a bus error 1539 | */ 1540 | Polygon& operator [] (unsigned i) 1541 | { if(i==0){return outer_boundary_;} else{return holes_[i-1];} } 1542 | //Mutators 1543 | /** \brief raw access to vertices via flattened index 1544 | * 1545 | * By flattened index is intended the label given to a vertex if 1546 | * you were to label all the vertices from 0 to n-1 (where n is 1547 | * the number of vertices representing the Environment) starting 1548 | * with the first vertex of the outer boundary and progressing in 1549 | * order through all the remaining vertices of the outer boundary 1550 | * and holes. 1551 | * \author Karl J. Obermeyer 1552 | * \remarks for efficiency, no bounds check; usually trying to 1553 | * access out of bounds causes a bus error. 1554 | */ 1555 | Point& operator () (unsigned k); 1556 | /// set outer boundary 1557 | void set_outer_boundary(const Polygon& polygon_temp) 1558 | { outer_boundary_ = polygon_temp; update_flattened_index_key(); } 1559 | /// add hole 1560 | void add_hole(const Polygon& polygon_temp) 1561 | { holes_.push_back(polygon_temp); update_flattened_index_key(); } 1562 | /** \brief enforces outer boundary vertices are listed ccw and 1563 | * holes listed cw, and that these lists begin with respective 1564 | * lexicographically smallest vertex 1565 | * 1566 | * \author Karl J. Obermeyer 1567 | * \remarks O(n) time complexity, where n is the number of 1568 | * vertices representing the Environment. Lex. comparison is very 1569 | * sensitive to perturbations if two Points nearly define a line 1570 | * parallel to one of the axes. 1571 | */ 1572 | void enforce_standard_form(); 1573 | /** \brief eliminates vertices which are (\a epsilon) - colinear 1574 | * with their respective neighbors 1575 | * 1576 | * \author Karl J. Obermeyer 1577 | * \post the Euclidean distance between each vertex and the line 1578 | * segment connecting its neighbors is at least \a epsilon 1579 | * \remarks time complexity O(n), where n is the number of 1580 | * vertices representing the the Environment 1581 | */ 1582 | void eliminate_redundant_vertices(double epsilon=0.0); 1583 | /** \brief reverse (cyclic) order of vertices belonging to holes 1584 | * only 1585 | * 1586 | * \remarks vertex first in each hole's list is held first 1587 | */ 1588 | void reverse_holes(); 1589 | private: 1590 | Polygon outer_boundary_; 1591 | //obstacles 1592 | std::vector holes_; 1593 | //allows constant time access to vertices via operator () with 1594 | //flattened index as argument 1595 | std::vector< std::pair > flattened_index_key_; 1596 | //Must call if size of outer_boundary and/or holes_ changes. Time 1597 | //complexity O(n), where n is the number of vertices representing 1598 | //the Environment. 1599 | void update_flattened_index_key(); 1600 | //converts flattened index to index pair (hole #, vertex #) in 1601 | //time O(n), where n is the number of vertices representing the 1602 | //Environment 1603 | std::pair one_to_two(unsigned k) const; 1604 | //node used for search tree of A* search in shortest_path() method 1605 | class Shortest_Path_Node 1606 | { 1607 | public: 1608 | //flattened index of corresponding Environment vertex 1609 | //convention vertex_index = n() => corresponds to start Point 1610 | //vertex_index = n() + 1 => corresponds to finish Point 1611 | unsigned vertex_index; 1612 | //pointer to self in search tree. 1613 | std::list::iterator search_tree_location; 1614 | //pointer to parent in search tree. 1615 | std::list::iterator parent_search_tree_location; 1616 | //Geodesic distance from start Point. 1617 | double cost_to_come; 1618 | //Euclidean distance to finish Point. 1619 | double estimated_cost_to_go; 1620 | //std::vector expand(); 1621 | bool operator < (const Shortest_Path_Node& spn2) const 1622 | { 1623 | double f1 = this->cost_to_come + this->estimated_cost_to_go; 1624 | double f2 = spn2.cost_to_come + spn2.estimated_cost_to_go; 1625 | if( f1 < f2 ) 1626 | return true; 1627 | else if( f2 < f1 ) 1628 | return false; 1629 | else if( this->vertex_index < spn2.vertex_index ) 1630 | return true; 1631 | else if( this->vertex_index > spn2.vertex_index ) 1632 | return false; 1633 | else if( &(*(this->parent_search_tree_location)) 1634 | < &(*(spn2.parent_search_tree_location)) ) 1635 | return true; 1636 | else 1637 | return false; 1638 | } 1639 | // print member data for debugging 1640 | void print() const 1641 | { 1642 | std::cout << " vertex_index = " << vertex_index << std::endl 1643 | << "parent's vertex_index = " 1644 | << parent_search_tree_location->vertex_index 1645 | << std::endl 1646 | << " cost_to_come = " << cost_to_come << std::endl 1647 | << " estimated_cost_to_go = " 1648 | << estimated_cost_to_go << std::endl; 1649 | } 1650 | }; 1651 | }; 1652 | 1653 | 1654 | /// printing Environment 1655 | std::ostream& operator << (std::ostream& outs, 1656 | const Environment& environment_temp); 1657 | 1658 | 1659 | /** \brief set of Guards represented by a list of Points 1660 | */ 1661 | class Guards 1662 | { 1663 | public: 1664 | friend class Visibility_Graph; 1665 | //Constructors 1666 | /// default to empty 1667 | Guards() { } 1668 | /** \brief construct from *.guards file 1669 | * 1670 | * \author Karl J. Obermeyer 1671 | */ 1672 | Guards(const std::string& filename); 1673 | /// construct from STL vector of Points 1674 | Guards(const std::vector& positions) 1675 | { positions_ = positions; } 1676 | //Accessors 1677 | /** \brief raw access to guard position Points 1678 | * 1679 | * \author Karl J. Obermeyer 1680 | * \remarks for efficiency, no bounds check; usually trying to 1681 | * access out of bounds causes a bus error 1682 | */ 1683 | const Point& operator [] (unsigned i) const { return positions_[i]; } 1684 | /// guard count 1685 | unsigned N() const { return positions_.size(); } 1686 | /// true iff positions are lexicographically ordered 1687 | bool are_lex_ordered() const; 1688 | /// true iff no two guards are w/in epsilon of each other 1689 | bool noncolocated(double epsilon=0.0) const; 1690 | /// true iff all guards are located in \a polygon_temp 1691 | bool in(const Polygon& polygon_temp, double epsilon=0.0) const; 1692 | /// true iff all guards are located in \a environment_temp 1693 | bool in(const Environment& environment_temp, double epsilon=0.0) const; 1694 | /** \brief Euclidean diameter 1695 | * 1696 | * \author Karl J. Obermeyer 1697 | * \pre greater than 0 guards 1698 | * \return maximum Euclidean distance between all pairs of 1699 | * vertices 1700 | * \remarks time complexity O(N^2), where N is the number of 1701 | * guards 1702 | */ 1703 | double diameter() const; 1704 | /** \brief box which fits snugly around the Guards 1705 | * 1706 | * \author Karl J. Obermeyer 1707 | * \pre greater than 0 guards 1708 | */ 1709 | Bounding_Box bbox() const; 1710 | /** \brief write list of positions to *.guards file 1711 | * 1712 | * Uses intuitive human and computer readable decimal format with 1713 | * display precision \a fios_precision_temp. 1714 | * \author Karl J. Obermeyer 1715 | * \pre \a fios_precision_temp >=1 1716 | */ 1717 | void write_to_file(const std::string& filename, 1718 | int fios_precision_temp=FIOS_PRECISION); 1719 | //Mutators 1720 | /** \brief raw access to guard position Points 1721 | * 1722 | * \author Karl J. Obermeyer 1723 | * \remarks for efficiency, no bounds check; usually trying to 1724 | * access out of bounds causes a bus error 1725 | */ 1726 | Point& operator [] (unsigned i) { return positions_[i]; } 1727 | /// add a guard 1728 | void push_back(const Point& point_temp) 1729 | { positions_.push_back(point_temp); } 1730 | /// set positions with STL vector of Points 1731 | void set_positions(const std::vector& positions_temp) 1732 | { positions_ = positions_temp; } 1733 | /** \brief sort positions in lexicographic order 1734 | * 1735 | * from (lowest x, then lowest y) to (highest x, then highest y) 1736 | * \author Karl J. Obermeyer 1737 | * \remarks time complexity O(N logN), where N is the guard count. 1738 | * Lex. comparison is very sensitive to perturbations if two 1739 | * Points nearly define a line parallel to one of the axes. 1740 | */ 1741 | void enforce_lex_order(); 1742 | /// reverse order of positions 1743 | void reverse(); 1744 | /** \brief relocate each guard to closest vertex if within 1745 | * \a epsilon of some vertex (of \a environment_temp) 1746 | * 1747 | * \author Karl J. Obermeyer 1748 | * \pre the guards' position data are numbers and \a environment_temp 1749 | * is nonempty 1750 | * \post if a guard was a Euclidean distance no greater 1751 | * than \a epsilon from any vertex of \a environment_temp, then it 1752 | * will be repositioned to coincide with the closest such vertex 1753 | * \remarks O(N*n) time complexity, where N is the guard count 1754 | * and n is the number of vertices in \a environment_temp. 1755 | */ 1756 | void snap_to_vertices_of(const Environment& environment_temp, 1757 | double epsilon=0.0); 1758 | 1759 | /** \brief relocate each guard to closest vertex if within 1760 | * \a epsilon of some vertex (of \a environment_temp) 1761 | * 1762 | * \author Karl J. Obermeyer 1763 | * \pre the guards' position data are numbers and \a polygon_temp 1764 | * is nonempty 1765 | * \post if a guard was a Euclidean distance no greater 1766 | * than \a epsilon from any vertex of \a polygon_temp, then it 1767 | * will be repositioned to coincide with the closest such vertex 1768 | * \remarks O(N*n) time complexity, where N is the guard count 1769 | * and n is the number of vertices in \a polygon_temp 1770 | */ 1771 | void snap_to_vertices_of(const Polygon& polygon_temp, 1772 | double epsilon=0.0); 1773 | /** \brief relocate each guard to closest Point on boundary if 1774 | * within \a epsilon of the boundary (of \a environment_temp) 1775 | * 1776 | * \author Karl J. Obermeyer 1777 | * \pre the guards' position data are numbers and \a environment_temp 1778 | * is nonempty 1779 | * \post If the calling Point was a Euclidean distance no greater 1780 | * than \a epsilon from the boundary of \a environment_temp, then it 1781 | * will be repositioned to it's projection onto that boundary 1782 | * \remarks O(N*n) time complexity, where N is the guard count and 1783 | * n is the number of vertices in \a environment_temp 1784 | */ 1785 | void snap_to_boundary_of(const Environment& environment_temp, 1786 | double epsilon=0.0); 1787 | /** \brief relocate each guard to closest Point on boundary if 1788 | * within \a epsilon of the boundary (of \a polygon_temp) 1789 | * 1790 | * \author Karl J. Obermeyer 1791 | * \pre the guards' position data are numbers and \a polygon_temp 1792 | * is nonempty 1793 | * \post If the calling Point was a Euclidean distance no greater 1794 | * than \a epsilon from the boundary of \a polygon_temp, then it 1795 | * will be repositioned to it's projection onto that boundary 1796 | * \remarks O(N*n) time complexity, where N is the guard count and 1797 | * n is the number of vertices in \a polygon_temp 1798 | */ 1799 | void snap_to_boundary_of(const Polygon& polygon_temp, 1800 | double epsilon=0.0); 1801 | private: 1802 | std::vector positions_; 1803 | }; 1804 | 1805 | 1806 | /// print Guards 1807 | std::ostream& operator << (std::ostream& outs, 1808 | const Guards& guards); 1809 | 1810 | 1811 | /** \brief visibility polygon of a Point in an Environment or Polygon 1812 | * 1813 | * A Visibility_Polygon represents the closure of the set of all 1814 | * points in an environment which are {\it clearly visible} from a 1815 | * point (the observer). Two Points p1 and p2 are (mutually) {\it 1816 | * clearly visible} in an environment iff the relative interior of 1817 | * the line segment connecting p1 and p2 does not intersect the 1818 | * boundary of the environment. 1819 | * 1820 | * \remarks average case time complexity O(n log(n)), where n is the 1821 | * number of vertices in the Evironment (resp. Polygon). Note the 1822 | * Standard Library's sort() function performs O(n log(n)) 1823 | * comparisons (both average and worst-case) and the sort() member 1824 | * function of an STL list performs "approximately O(n log(n)) 1825 | * comparisons". For robustness, any Point (observer) should be \a 1826 | * epsilon -snapped to the environment boundary and vertices before 1827 | * computing its Visibility_Polygon (use the Point methods 1828 | * snap_to_vertices_of(...) and snap_to_boundary_of(...) ). 1829 | */ 1830 | class Visibility_Polygon : public Polygon 1831 | { 1832 | public: 1833 | //Constructors 1834 | /// default to empty 1835 | Visibility_Polygon() { } 1836 | //:TRICKY: 1837 | /** \brief visibility set of a Point in an Environment 1838 | * 1839 | * \author Karl J. Obermeyer 1840 | * 1841 | * \pre \a observer is in \a environment_temp (w/in \a epsilon ) 1842 | * and has been epsilon-snapped to the Environment using the 1843 | * method Point::snap_to_boundary_of() followed by (order is 1844 | * important) Point::snap_to_vertices_of(). \a environment_temp 1845 | * must be \a epsilon -valid. Test with 1846 | * Environment::is_valid(epsilon). 1847 | * 1848 | * \remarks O(n log(n)) average case time complexity, where n is the 1849 | * number of vertices in the Evironment (resp. Polygon). 1850 | */ 1851 | Visibility_Polygon(const Point& observer, 1852 | const Environment& environment_temp, 1853 | double epsilon=0.0); 1854 | /** \brief visibility set of a Point in a Polygon 1855 | * 1856 | * \pre \a observer is in \a polygon_temp (w/in \a epsilon ) and 1857 | * has been epsilon-snapped to the Polygon using the methods 1858 | * Point::snap_to_vertices_of() and Point::snap_to_boundary_of(). 1859 | * \a environment_temp must be \a epsilon -valid. Test with 1860 | * Environment::is_valid(epsilon). 1861 | * 1862 | * \remarks less efficient because constructs an Environment from 1863 | * a Polygon and then calls the other Visibility_Polygon constructor. 1864 | * O(n log(n)) average case time complexity, where n is the 1865 | * number of vertices in the Evironment (resp. Polygon). 1866 | */ 1867 | Visibility_Polygon(const Point& observer, 1868 | const Polygon& polygon_temp, 1869 | double epsilon=0.0); 1870 | //Accessors 1871 | //std::vector get_gap_edges(double epsilon=0.0) { return gap_edges_; } 1872 | /// location of observer which induced the visibility polygon 1873 | Point observer() const 1874 | { return observer_; } 1875 | //Mutators 1876 | private: 1877 | //ith entry of gap_edges is true iff the edge following ith vertex 1878 | //is a gap edge (not solid). 1879 | //std::vector gap_edges_; 1880 | Point observer_; 1881 | 1882 | struct Polar_Edge 1883 | { 1884 | Polar_Point first; 1885 | Polar_Point second; 1886 | Polar_Edge() { } 1887 | Polar_Edge(const Polar_Point& ppoint1, 1888 | const Polar_Point& ppoint2) : 1889 | first(ppoint1), second(ppoint2) {} 1890 | }; 1891 | 1892 | class Polar_Point_With_Edge_Info : public Polar_Point 1893 | { 1894 | public: 1895 | std::list::iterator incident_edge; 1896 | bool is_first; //True iff polar_point is the first_point of the 1897 | //Polar_Edge pointed to by 1898 | //incident_edge. 1899 | void set_polar_point(const Polar_Point& ppoint_temp) 1900 | { 1901 | set_polar_origin( ppoint_temp.polar_origin() ); 1902 | set_x( ppoint_temp.x() ); 1903 | set_y( ppoint_temp.y() ); 1904 | set_range( ppoint_temp.range() ); 1905 | set_bearing( ppoint_temp.bearing() ); 1906 | } 1907 | //The operator < is the same as for Polar_Point with one 1908 | //exception. If two vertices have equal coordinates, but one is 1909 | //the first point of its respecitve edge and the other is the 1910 | //second point of its respective edge, then the vertex which is 1911 | //the second point of its respective edge is considered 1912 | //lexicographically smaller. 1913 | friend bool operator < (const Polar_Point_With_Edge_Info& ppwei1, 1914 | const Polar_Point_With_Edge_Info& ppwei2) 1915 | { 1916 | if( Polar_Point(ppwei1) == Polar_Point(ppwei2) 1917 | and !ppwei1.is_first and ppwei2.is_first ) 1918 | return true; 1919 | else 1920 | return Polar_Point(ppwei1) < Polar_Point(ppwei2); 1921 | } 1922 | }; 1923 | 1924 | //Strict weak ordering (acts like <) for pointers to Polar_Edges. 1925 | //Used to sort the priority_queue q2 used in the radial line sweep 1926 | //of Visibility_Polygon constructors. Let p1 be a pointer to 1927 | //Polar_Edge e1 and p2 be a pointer to Polar_Edge e2. Then p1 is 1928 | //considered greater (higher priority) than p2 if the distance 1929 | //from the observer (pointed to by observer_pointer) to e1 along 1930 | //the direction to current_vertex is smaller than the distance 1931 | //from the observer to e2 along the direction to current_vertex. 1932 | class Incident_Edge_Compare 1933 | { 1934 | const Point *const observer_pointer; 1935 | const Polar_Point_With_Edge_Info *const current_vertex_pointer; 1936 | double epsilon; 1937 | public: 1938 | Incident_Edge_Compare(const Point& observer, 1939 | const Polar_Point_With_Edge_Info& current_vertex, 1940 | double epsilon_temp) : 1941 | observer_pointer(&observer), 1942 | current_vertex_pointer(¤t_vertex), 1943 | epsilon(epsilon_temp) { } 1944 | bool operator () (std::list::iterator e1, 1945 | std::list::iterator e2) const 1946 | { 1947 | Polar_Point k1, k2; 1948 | Line_Segment xing1 = intersection( Ray(*observer_pointer, 1949 | current_vertex_pointer->bearing()), 1950 | Line_Segment(e1->first, 1951 | e1->second), 1952 | epsilon); 1953 | Line_Segment xing2 = intersection( Ray(*observer_pointer, 1954 | current_vertex_pointer->bearing()), 1955 | Line_Segment(e2->first, 1956 | e2->second), 1957 | epsilon); 1958 | if( xing1.size() > 0 and xing2.size() > 0 ){ 1959 | k1 = Polar_Point( *observer_pointer, 1960 | xing1.first() ); 1961 | k2 = Polar_Point( *observer_pointer, 1962 | xing2.first() ); 1963 | if( k1.range() <= k2.range() ) 1964 | return false; 1965 | return true; 1966 | } 1967 | //Otherwise infeasible edges are given higher priority, so they 1968 | //get pushed out the top of the priority_queue's (q2's) 1969 | //heap. 1970 | else if( xing1.size() == 0 and xing2.size() > 0 ) 1971 | return false; 1972 | else if( xing1.size() > 0 and xing2.size() == 0 ) 1973 | return true; 1974 | else 1975 | return true; 1976 | } 1977 | }; 1978 | 1979 | bool is_spike( const Point& observer, 1980 | const Point& point1, 1981 | const Point& point2, 1982 | const Point& point3, 1983 | double epsilon=0.0 ) const; 1984 | 1985 | //For eliminating spikes as they appear. In the 1986 | //Visibility_Polygon constructors, these are checked every time a 1987 | //Point is added to vertices. 1988 | void chop_spikes_at_back(const Point& observer, 1989 | double epsilon); 1990 | void chop_spikes_at_wrap_around(const Point& observer, 1991 | double epsilon); 1992 | void chop_spikes(const Point& observer, 1993 | double epsilon); 1994 | //For debugging Visibility_Polygon constructors. 1995 | //Prints current_vertex and active_edge data to screen. 1996 | void print_cv_and_ae(const Polar_Point_With_Edge_Info& current_vertex, 1997 | const std::list::iterator& 1998 | active_edge); 1999 | }; 2000 | 2001 | 2002 | /** \brief visibility graph of points in an Environment, 2003 | * represented by adjacency matrix 2004 | * 2005 | * \remarks used for shortest path planning in the 2006 | * Environment::shortest_path() method 2007 | * 2008 | * \todo Add method to prune edges for faster shortest path 2009 | * calculation, e.g., exclude concave vertices and only include 2010 | * tangent edges as described in ``Robot Motion Planning" (Ch. 4 2011 | * Sec. 1) by J.C. Latombe. 2012 | */ 2013 | class Visibility_Graph 2014 | { 2015 | public: 2016 | //Constructors 2017 | /// default to empty 2018 | Visibility_Graph() { n_=0; adjacency_matrix_ = NULL; } 2019 | /// copy 2020 | Visibility_Graph( const Visibility_Graph& vg2 ); 2021 | /** \brief construct the visibility graph of Environment vertices 2022 | * 2023 | * \author Karl J. Obermeyer 2024 | * 2025 | * \pre \a environment must be \a epsilon -valid. Test with 2026 | * Environment::is_valid(epsilon). 2027 | * 2028 | * \remarks Currently this constructor simply computes the 2029 | * Visibility_Polygon of each vertex and checks inclusion of the 2030 | * other vertices, taking time complexity O(n^3), where n is the 2031 | * number of vertices representing the Environment. This time 2032 | * complexity is not optimal. As mentioned in ``Robot Motion 2033 | * Planning" by J.C. Latombe p.157, there are algorithms able to 2034 | * construct a visibility graph for a polygonal environment with 2035 | * holes in time O(n^2). The nonoptimal algorithm is being used 2036 | * temporarily because of (1) its ease to implement using the 2037 | * Visibility_Polygon class, and (2) its apparent robustness. 2038 | * Implementing the optimal algorithm robustly is future work. 2039 | */ 2040 | Visibility_Graph(const Environment& environment, double epsilon=0.0); 2041 | //Constructors 2042 | /** \brief construct the visibility graph of Points in an Environment 2043 | * 2044 | * \pre \a environment must be \a epsilon -valid. Test with 2045 | * Environment::is_valid(epsilon). 2046 | * 2047 | * \author Karl J. Obermeyer \remarks Currently this constructor 2048 | * simply computes the Visibility_Polygon of each Point and checks 2049 | * inclusion of the other Points, taking time complexity 2050 | * O(N n log(n) + N^2 n), where N is the number of Points and n is 2051 | * the number of vertices representing the Environment. This time 2052 | * complexity is not optimal, but has been used for 2053 | * simplicity. More efficient algorithms are discussed in ``Robot 2054 | * Motion Planning" by J.C. Latombe p.157. 2055 | */ 2056 | Visibility_Graph(const std::vector points, 2057 | const Environment& environment, double epsilon=0.0); 2058 | //Constructors 2059 | /** \brief construct the visibility graph of Guards in an Environment 2060 | * 2061 | * \pre \a start and \a finish must be in the environment. 2062 | * Environment must be \a epsilon -valid. Test with 2063 | * Environment::is_valid(epsilon). 2064 | * 2065 | * \author Karl J. Obermeyer 2066 | * \remarks Currently this constructor simply computes the 2067 | * Visibility_Polygon of each guard and checks inclusion of the 2068 | * other guards, taking time complexity O(N n log(n) + N^2 n), 2069 | * where N is the number of guards and n is the number of vertices 2070 | * representing the Environment. This time complexity is not 2071 | * optimal, but has been used for simplicity. More efficient 2072 | * algorithms are discussed in ``Robot Motion Planning" by 2073 | * J.C. Latombe p.157. 2074 | */ 2075 | Visibility_Graph(const Guards& guards, 2076 | const Environment& environment, double epsilon=0.0); 2077 | //Accessors 2078 | /** \brief raw access to adjacency matrix data 2079 | * 2080 | * \author Karl J. Obermeyer 2081 | * \param i1 Polygon index of first vertex 2082 | * \param j1 index of first vertex within its Polygon 2083 | * \param i2 Polygon index of second vertex 2084 | * \param j2 index of second vertex within its Polygon 2085 | * \return true iff first vertex is visible from second vertex 2086 | * \remarks for efficiency, no bounds check; usually trying to 2087 | * access out of bounds causes a bus error 2088 | */ 2089 | bool operator () (unsigned i1, 2090 | unsigned j1, 2091 | unsigned i2, 2092 | unsigned j2) const; 2093 | /** \brief raw access to adjacency matrix data via flattened 2094 | * indices 2095 | * 2096 | * By flattened index is intended the label given to a vertex if 2097 | * you were to label all the vertices from 0 to n-1 (where n is 2098 | * the number of vertices representing the Environment) starting 2099 | * with the first vertex of the outer boundary and progressing in 2100 | * order through all the remaining vertices of the outer boundary 2101 | * and holes. 2102 | * \author Karl J. Obermeyer 2103 | * \param k1 flattened index of first vertex 2104 | * \param k1 flattened index of second vertex 2105 | * \return true iff first vertex is visible from second vertex 2106 | * \remarks for efficiency, no bounds check; usually trying to 2107 | * access out of bounds causes a bus error 2108 | */ 2109 | bool operator () (unsigned k1, 2110 | unsigned k2) const; 2111 | /// \brief total number of vertices in corresponding Environment 2112 | unsigned n() const { return n_; } 2113 | //Mutators 2114 | /** \brief raw access to adjacency matrix data 2115 | * 2116 | * \author Karl J. Obermeyer 2117 | * \param i1 Polygon index of first vertex 2118 | * \param j1 index of first vertex within its Polygon 2119 | * \param i2 Polygon index of second vertex 2120 | * \param j2 index of second vertex within its Polygon 2121 | * \return true iff first vertex is visible from second vertex 2122 | * \remarks for efficiency, no bounds check; usually trying to 2123 | * access out of bounds causes a bus error 2124 | */ 2125 | bool& operator () (unsigned i1, 2126 | unsigned j1, 2127 | unsigned i2, 2128 | unsigned j2); 2129 | /** \brief raw access to adjacency matrix data via flattened 2130 | * indices 2131 | * 2132 | * By flattened index is intended the label given to a vertex if 2133 | * you were to label all the vertices from 0 to n-1 (where n is 2134 | * the number of vertices representing the Environment) starting 2135 | * with the first vertex of the outer boundary and progressing in 2136 | * order through all the remaining vertices of the outer boundary 2137 | * and holes. 2138 | * \author Karl J. Obermeyer 2139 | * \param k1 flattened index of first vertex 2140 | * \param k1 flattened index of second vertex 2141 | * \return true iff first vertex is visible from second vertex 2142 | * \remarks for efficiency, no bounds check; usually trying to 2143 | * access out of bounds causes a bus error 2144 | */ 2145 | bool& operator () (unsigned k1, 2146 | unsigned k2); 2147 | /// assignment operator 2148 | Visibility_Graph& operator = 2149 | (const Visibility_Graph& visibility_graph_temp); 2150 | /// destructor 2151 | virtual ~Visibility_Graph(); 2152 | private: 2153 | //total number of vertices of corresponding Environment 2154 | unsigned n_; 2155 | //the number of vertices in each Polygon of corresponding Environment 2156 | std::vector vertex_counts_; 2157 | // n_-by-n_ adjacency matrix data stored as 2D dynamic array 2158 | bool **adjacency_matrix_; 2159 | //converts vertex pairs (hole #, vertex #) to flattened index 2160 | unsigned two_to_one(unsigned i, 2161 | unsigned j) const; 2162 | }; 2163 | 2164 | 2165 | /// print Visibility_Graph adjacency matrix 2166 | std::ostream& operator << (std::ostream& outs, 2167 | const Visibility_Graph& visibility_graph); 2168 | 2169 | } 2170 | 2171 | #endif //VISILIBITY_H 2172 | -------------------------------------------------------------------------------- /visilibity.i: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | PyVisiLibity: a Python binding of VisiLibity1 4 | Copyright (C) 2018 Yu Cao < University of Southampton> Yu.Cao at soton.ac.uk 5 | Originally by Stefanie T. of MIT, United States 6 | 7 | PyVisiLibity is free software: you can redistribute it and/or modify it under 8 | the terms of the GNU Lesser General Public License as published by the 9 | Free Software Foundation, either version 3 of the License, or (at your 10 | option) any later version. 11 | PyVisiLibity is distributed in the hope that it will be useful, but WITHOUT 12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 14 | License for more details. 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with PyVisiLibity. If not, see . 17 | 18 | 19 | */ 20 | %module visilibity 21 | #pragma SWIG nowarn=501 22 | #pragma SWIG nowarn=501,505,401 23 | %{ 24 | 25 | #include "visilibity.hpp" 26 | %} 27 | %include std_vector.i 28 | namespace std { 29 | %template(pointList) vector; 30 | %template(polygonList) vector; 31 | } 32 | 33 | 34 | %include visilibity.hpp 35 | 36 | 37 | %extend VisiLibity::Polygon { 38 | Point __getitem__(unsigned i) { 39 | return (*self)[i]; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /visilibity.py: -------------------------------------------------------------------------------- 1 | # This file was automatically generated by SWIG (http://www.swig.org). 2 | # Version 3.0.12 3 | # 4 | # Do not make changes to this file unless you know what you are doing--modify 5 | # the SWIG interface file instead. 6 | 7 | from sys import version_info as _swig_python_version_info 8 | if _swig_python_version_info >= (2, 7, 0): 9 | def swig_import_helper(): 10 | import importlib 11 | pkg = __name__.rpartition('.')[0] 12 | mname = '.'.join((pkg, '_visilibity')).lstrip('.') 13 | try: 14 | return importlib.import_module(mname) 15 | except ImportError: 16 | return importlib.import_module('_visilibity') 17 | _visilibity = swig_import_helper() 18 | del swig_import_helper 19 | elif _swig_python_version_info >= (2, 6, 0): 20 | def swig_import_helper(): 21 | from os.path import dirname 22 | import imp 23 | fp = None 24 | try: 25 | fp, pathname, description = imp.find_module('_visilibity', [dirname(__file__)]) 26 | except ImportError: 27 | import _visilibity 28 | return _visilibity 29 | try: 30 | _mod = imp.load_module('_visilibity', fp, pathname, description) 31 | finally: 32 | if fp is not None: 33 | fp.close() 34 | return _mod 35 | _visilibity = swig_import_helper() 36 | del swig_import_helper 37 | else: 38 | import _visilibity 39 | del _swig_python_version_info 40 | 41 | try: 42 | _swig_property = property 43 | except NameError: 44 | pass # Python < 2.2 doesn't have 'property'. 45 | 46 | try: 47 | import builtins as __builtin__ 48 | except ImportError: 49 | import __builtin__ 50 | 51 | def _swig_setattr_nondynamic(self, class_type, name, value, static=1): 52 | if (name == "thisown"): 53 | return self.this.own(value) 54 | if (name == "this"): 55 | if type(value).__name__ == 'SwigPyObject': 56 | self.__dict__[name] = value 57 | return 58 | method = class_type.__swig_setmethods__.get(name, None) 59 | if method: 60 | return method(self, value) 61 | if (not static): 62 | if _newclass: 63 | object.__setattr__(self, name, value) 64 | else: 65 | self.__dict__[name] = value 66 | else: 67 | raise AttributeError("You cannot add attributes to %s" % self) 68 | 69 | 70 | def _swig_setattr(self, class_type, name, value): 71 | return _swig_setattr_nondynamic(self, class_type, name, value, 0) 72 | 73 | 74 | def _swig_getattr(self, class_type, name): 75 | if (name == "thisown"): 76 | return self.this.own() 77 | method = class_type.__swig_getmethods__.get(name, None) 78 | if method: 79 | return method(self) 80 | raise AttributeError("'%s' object has no attribute '%s'" % (class_type.__name__, name)) 81 | 82 | 83 | def _swig_repr(self): 84 | try: 85 | strthis = "proxy of " + self.this.__repr__() 86 | except __builtin__.Exception: 87 | strthis = "" 88 | return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,) 89 | 90 | try: 91 | _object = object 92 | _newclass = 1 93 | except __builtin__.Exception: 94 | class _object: 95 | pass 96 | _newclass = 0 97 | 98 | class SwigPyIterator(_object): 99 | __swig_setmethods__ = {} 100 | __setattr__ = lambda self, name, value: _swig_setattr(self, SwigPyIterator, name, value) 101 | __swig_getmethods__ = {} 102 | __getattr__ = lambda self, name: _swig_getattr(self, SwigPyIterator, name) 103 | 104 | def __init__(self, *args, **kwargs): 105 | raise AttributeError("No constructor defined - class is abstract") 106 | __repr__ = _swig_repr 107 | __swig_destroy__ = _visilibity.delete_SwigPyIterator 108 | __del__ = lambda self: None 109 | 110 | def value(self): 111 | return _visilibity.SwigPyIterator_value(self) 112 | 113 | def incr(self, n=1): 114 | return _visilibity.SwigPyIterator_incr(self, n) 115 | 116 | def decr(self, n=1): 117 | return _visilibity.SwigPyIterator_decr(self, n) 118 | 119 | def distance(self, x): 120 | return _visilibity.SwigPyIterator_distance(self, x) 121 | 122 | def equal(self, x): 123 | return _visilibity.SwigPyIterator_equal(self, x) 124 | 125 | def copy(self): 126 | return _visilibity.SwigPyIterator_copy(self) 127 | 128 | def next(self): 129 | return _visilibity.SwigPyIterator_next(self) 130 | 131 | def __next__(self): 132 | return _visilibity.SwigPyIterator___next__(self) 133 | 134 | def previous(self): 135 | return _visilibity.SwigPyIterator_previous(self) 136 | 137 | def advance(self, n): 138 | return _visilibity.SwigPyIterator_advance(self, n) 139 | 140 | def __eq__(self, x): 141 | return _visilibity.SwigPyIterator___eq__(self, x) 142 | 143 | def __ne__(self, x): 144 | return _visilibity.SwigPyIterator___ne__(self, x) 145 | 146 | def __iadd__(self, n): 147 | return _visilibity.SwigPyIterator___iadd__(self, n) 148 | 149 | def __isub__(self, n): 150 | return _visilibity.SwigPyIterator___isub__(self, n) 151 | 152 | def __add__(self, n): 153 | return _visilibity.SwigPyIterator___add__(self, n) 154 | 155 | def __sub__(self, *args): 156 | return _visilibity.SwigPyIterator___sub__(self, *args) 157 | def __iter__(self): 158 | return self 159 | SwigPyIterator_swigregister = _visilibity.SwigPyIterator_swigregister 160 | SwigPyIterator_swigregister(SwigPyIterator) 161 | 162 | class pointList(_object): 163 | __swig_setmethods__ = {} 164 | __setattr__ = lambda self, name, value: _swig_setattr(self, pointList, name, value) 165 | __swig_getmethods__ = {} 166 | __getattr__ = lambda self, name: _swig_getattr(self, pointList, name) 167 | __repr__ = _swig_repr 168 | 169 | def iterator(self): 170 | return _visilibity.pointList_iterator(self) 171 | def __iter__(self): 172 | return self.iterator() 173 | 174 | def __nonzero__(self): 175 | return _visilibity.pointList___nonzero__(self) 176 | 177 | def __bool__(self): 178 | return _visilibity.pointList___bool__(self) 179 | 180 | def __len__(self): 181 | return _visilibity.pointList___len__(self) 182 | 183 | def __getslice__(self, i, j): 184 | return _visilibity.pointList___getslice__(self, i, j) 185 | 186 | def __setslice__(self, *args): 187 | return _visilibity.pointList___setslice__(self, *args) 188 | 189 | def __delslice__(self, i, j): 190 | return _visilibity.pointList___delslice__(self, i, j) 191 | 192 | def __delitem__(self, *args): 193 | return _visilibity.pointList___delitem__(self, *args) 194 | 195 | def __getitem__(self, *args): 196 | return _visilibity.pointList___getitem__(self, *args) 197 | 198 | def __setitem__(self, *args): 199 | return _visilibity.pointList___setitem__(self, *args) 200 | 201 | def pop(self): 202 | return _visilibity.pointList_pop(self) 203 | 204 | def append(self, x): 205 | return _visilibity.pointList_append(self, x) 206 | 207 | def empty(self): 208 | return _visilibity.pointList_empty(self) 209 | 210 | def size(self): 211 | return _visilibity.pointList_size(self) 212 | 213 | def swap(self, v): 214 | return _visilibity.pointList_swap(self, v) 215 | 216 | def begin(self): 217 | return _visilibity.pointList_begin(self) 218 | 219 | def end(self): 220 | return _visilibity.pointList_end(self) 221 | 222 | def rbegin(self): 223 | return _visilibity.pointList_rbegin(self) 224 | 225 | def rend(self): 226 | return _visilibity.pointList_rend(self) 227 | 228 | def clear(self): 229 | return _visilibity.pointList_clear(self) 230 | 231 | def get_allocator(self): 232 | return _visilibity.pointList_get_allocator(self) 233 | 234 | def pop_back(self): 235 | return _visilibity.pointList_pop_back(self) 236 | 237 | def erase(self, *args): 238 | return _visilibity.pointList_erase(self, *args) 239 | 240 | def __init__(self, *args): 241 | this = _visilibity.new_pointList(*args) 242 | try: 243 | self.this.append(this) 244 | except __builtin__.Exception: 245 | self.this = this 246 | 247 | def push_back(self, x): 248 | return _visilibity.pointList_push_back(self, x) 249 | 250 | def front(self): 251 | return _visilibity.pointList_front(self) 252 | 253 | def back(self): 254 | return _visilibity.pointList_back(self) 255 | 256 | def assign(self, n, x): 257 | return _visilibity.pointList_assign(self, n, x) 258 | 259 | def resize(self, *args): 260 | return _visilibity.pointList_resize(self, *args) 261 | 262 | def insert(self, *args): 263 | return _visilibity.pointList_insert(self, *args) 264 | 265 | def reserve(self, n): 266 | return _visilibity.pointList_reserve(self, n) 267 | 268 | def capacity(self): 269 | return _visilibity.pointList_capacity(self) 270 | __swig_destroy__ = _visilibity.delete_pointList 271 | __del__ = lambda self: None 272 | pointList_swigregister = _visilibity.pointList_swigregister 273 | pointList_swigregister(pointList) 274 | 275 | class polygonList(_object): 276 | __swig_setmethods__ = {} 277 | __setattr__ = lambda self, name, value: _swig_setattr(self, polygonList, name, value) 278 | __swig_getmethods__ = {} 279 | __getattr__ = lambda self, name: _swig_getattr(self, polygonList, name) 280 | __repr__ = _swig_repr 281 | 282 | def iterator(self): 283 | return _visilibity.polygonList_iterator(self) 284 | def __iter__(self): 285 | return self.iterator() 286 | 287 | def __nonzero__(self): 288 | return _visilibity.polygonList___nonzero__(self) 289 | 290 | def __bool__(self): 291 | return _visilibity.polygonList___bool__(self) 292 | 293 | def __len__(self): 294 | return _visilibity.polygonList___len__(self) 295 | 296 | def __getslice__(self, i, j): 297 | return _visilibity.polygonList___getslice__(self, i, j) 298 | 299 | def __setslice__(self, *args): 300 | return _visilibity.polygonList___setslice__(self, *args) 301 | 302 | def __delslice__(self, i, j): 303 | return _visilibity.polygonList___delslice__(self, i, j) 304 | 305 | def __delitem__(self, *args): 306 | return _visilibity.polygonList___delitem__(self, *args) 307 | 308 | def __getitem__(self, *args): 309 | return _visilibity.polygonList___getitem__(self, *args) 310 | 311 | def __setitem__(self, *args): 312 | return _visilibity.polygonList___setitem__(self, *args) 313 | 314 | def pop(self): 315 | return _visilibity.polygonList_pop(self) 316 | 317 | def append(self, x): 318 | return _visilibity.polygonList_append(self, x) 319 | 320 | def empty(self): 321 | return _visilibity.polygonList_empty(self) 322 | 323 | def size(self): 324 | return _visilibity.polygonList_size(self) 325 | 326 | def swap(self, v): 327 | return _visilibity.polygonList_swap(self, v) 328 | 329 | def begin(self): 330 | return _visilibity.polygonList_begin(self) 331 | 332 | def end(self): 333 | return _visilibity.polygonList_end(self) 334 | 335 | def rbegin(self): 336 | return _visilibity.polygonList_rbegin(self) 337 | 338 | def rend(self): 339 | return _visilibity.polygonList_rend(self) 340 | 341 | def clear(self): 342 | return _visilibity.polygonList_clear(self) 343 | 344 | def get_allocator(self): 345 | return _visilibity.polygonList_get_allocator(self) 346 | 347 | def pop_back(self): 348 | return _visilibity.polygonList_pop_back(self) 349 | 350 | def erase(self, *args): 351 | return _visilibity.polygonList_erase(self, *args) 352 | 353 | def __init__(self, *args): 354 | this = _visilibity.new_polygonList(*args) 355 | try: 356 | self.this.append(this) 357 | except __builtin__.Exception: 358 | self.this = this 359 | 360 | def push_back(self, x): 361 | return _visilibity.polygonList_push_back(self, x) 362 | 363 | def front(self): 364 | return _visilibity.polygonList_front(self) 365 | 366 | def back(self): 367 | return _visilibity.polygonList_back(self) 368 | 369 | def assign(self, n, x): 370 | return _visilibity.polygonList_assign(self, n, x) 371 | 372 | def resize(self, *args): 373 | return _visilibity.polygonList_resize(self, *args) 374 | 375 | def insert(self, *args): 376 | return _visilibity.polygonList_insert(self, *args) 377 | 378 | def reserve(self, n): 379 | return _visilibity.polygonList_reserve(self, n) 380 | 381 | def capacity(self): 382 | return _visilibity.polygonList_capacity(self) 383 | __swig_destroy__ = _visilibity.delete_polygonList 384 | __del__ = lambda self: None 385 | polygonList_swigregister = _visilibity.polygonList_swigregister 386 | polygonList_swigregister(polygonList) 387 | 388 | 389 | def uniform_random_sample(lower_bound, upper_bound): 390 | return _visilibity.uniform_random_sample(lower_bound, upper_bound) 391 | uniform_random_sample = _visilibity.uniform_random_sample 392 | class Bounding_Box(_object): 393 | __swig_setmethods__ = {} 394 | __setattr__ = lambda self, name, value: _swig_setattr(self, Bounding_Box, name, value) 395 | __swig_getmethods__ = {} 396 | __getattr__ = lambda self, name: _swig_getattr(self, Bounding_Box, name) 397 | __repr__ = _swig_repr 398 | __swig_setmethods__["x_min"] = _visilibity.Bounding_Box_x_min_set 399 | __swig_getmethods__["x_min"] = _visilibity.Bounding_Box_x_min_get 400 | if _newclass: 401 | x_min = _swig_property(_visilibity.Bounding_Box_x_min_get, _visilibity.Bounding_Box_x_min_set) 402 | __swig_setmethods__["x_max"] = _visilibity.Bounding_Box_x_max_set 403 | __swig_getmethods__["x_max"] = _visilibity.Bounding_Box_x_max_get 404 | if _newclass: 405 | x_max = _swig_property(_visilibity.Bounding_Box_x_max_get, _visilibity.Bounding_Box_x_max_set) 406 | __swig_setmethods__["y_min"] = _visilibity.Bounding_Box_y_min_set 407 | __swig_getmethods__["y_min"] = _visilibity.Bounding_Box_y_min_get 408 | if _newclass: 409 | y_min = _swig_property(_visilibity.Bounding_Box_y_min_get, _visilibity.Bounding_Box_y_min_set) 410 | __swig_setmethods__["y_max"] = _visilibity.Bounding_Box_y_max_set 411 | __swig_getmethods__["y_max"] = _visilibity.Bounding_Box_y_max_get 412 | if _newclass: 413 | y_max = _swig_property(_visilibity.Bounding_Box_y_max_get, _visilibity.Bounding_Box_y_max_set) 414 | 415 | def __init__(self): 416 | this = _visilibity.new_Bounding_Box() 417 | try: 418 | self.this.append(this) 419 | except __builtin__.Exception: 420 | self.this = this 421 | __swig_destroy__ = _visilibity.delete_Bounding_Box 422 | __del__ = lambda self: None 423 | Bounding_Box_swigregister = _visilibity.Bounding_Box_swigregister 424 | Bounding_Box_swigregister(Bounding_Box) 425 | cvar = _visilibity.cvar 426 | FIOS_PRECISION = cvar.FIOS_PRECISION 427 | 428 | class Point(_object): 429 | __swig_setmethods__ = {} 430 | __setattr__ = lambda self, name, value: _swig_setattr(self, Point, name, value) 431 | __swig_getmethods__ = {} 432 | __getattr__ = lambda self, name: _swig_getattr(self, Point, name) 433 | __repr__ = _swig_repr 434 | 435 | def __init__(self, *args): 436 | this = _visilibity.new_Point(*args) 437 | try: 438 | self.this.append(this) 439 | except __builtin__.Exception: 440 | self.this = this 441 | 442 | def x(self): 443 | return _visilibity.Point_x(self) 444 | 445 | def y(self): 446 | return _visilibity.Point_y(self) 447 | 448 | def projection_onto(self, *args): 449 | return _visilibity.Point_projection_onto(self, *args) 450 | 451 | def projection_onto_vertices_of(self, *args): 452 | return _visilibity.Point_projection_onto_vertices_of(self, *args) 453 | 454 | def projection_onto_boundary_of(self, *args): 455 | return _visilibity.Point_projection_onto_boundary_of(self, *args) 456 | 457 | def on_boundary_of(self, *args): 458 | return _visilibity.Point_on_boundary_of(self, *args) 459 | 460 | def in_relative_interior_of(self, line_segment_temp, epsilon=0.0): 461 | return _visilibity.Point_in_relative_interior_of(self, line_segment_temp, epsilon) 462 | 463 | def _in(self, *args): 464 | return _visilibity.Point__in(self, *args) 465 | 466 | def is_endpoint_of(self, line_segment_temp, epsilon=0.0): 467 | return _visilibity.Point_is_endpoint_of(self, line_segment_temp, epsilon) 468 | 469 | def set_x(self, x_temp): 470 | return _visilibity.Point_set_x(self, x_temp) 471 | 472 | def set_y(self, y_temp): 473 | return _visilibity.Point_set_y(self, y_temp) 474 | 475 | def snap_to_vertices_of(self, *args): 476 | return _visilibity.Point_snap_to_vertices_of(self, *args) 477 | 478 | def snap_to_boundary_of(self, *args): 479 | return _visilibity.Point_snap_to_boundary_of(self, *args) 480 | __swig_destroy__ = _visilibity.delete_Point 481 | __del__ = lambda self: None 482 | Point_swigregister = _visilibity.Point_swigregister 483 | Point_swigregister(Point) 484 | 485 | 486 | def __mul__(*args): 487 | return _visilibity.__mul__(*args) 488 | __mul__ = _visilibity.__mul__ 489 | 490 | def cross(point1, point2): 491 | return _visilibity.cross(point1, point2) 492 | cross = _visilibity.cross 493 | class Line_Segment(_object): 494 | __swig_setmethods__ = {} 495 | __setattr__ = lambda self, name, value: _swig_setattr(self, Line_Segment, name, value) 496 | __swig_getmethods__ = {} 497 | __getattr__ = lambda self, name: _swig_getattr(self, Line_Segment, name) 498 | __repr__ = _swig_repr 499 | 500 | def __init__(self, *args): 501 | this = _visilibity.new_Line_Segment(*args) 502 | try: 503 | self.this.append(this) 504 | except __builtin__.Exception: 505 | self.this = this 506 | 507 | def first(self): 508 | return _visilibity.Line_Segment_first(self) 509 | 510 | def second(self): 511 | return _visilibity.Line_Segment_second(self) 512 | 513 | def size(self): 514 | return _visilibity.Line_Segment_size(self) 515 | 516 | def midpoint(self): 517 | return _visilibity.Line_Segment_midpoint(self) 518 | 519 | def length(self): 520 | return _visilibity.Line_Segment_length(self) 521 | 522 | def is_in_standard_form(self): 523 | return _visilibity.Line_Segment_is_in_standard_form(self) 524 | 525 | def set_first(self, point_temp, epsilon=0.0): 526 | return _visilibity.Line_Segment_set_first(self, point_temp, epsilon) 527 | 528 | def set_second(self, point_temp, epsilon=0.0): 529 | return _visilibity.Line_Segment_set_second(self, point_temp, epsilon) 530 | 531 | def reverse(self): 532 | return _visilibity.Line_Segment_reverse(self) 533 | 534 | def enforce_standard_form(self): 535 | return _visilibity.Line_Segment_enforce_standard_form(self) 536 | 537 | def clear(self): 538 | return _visilibity.Line_Segment_clear(self) 539 | __swig_destroy__ = _visilibity.delete_Line_Segment 540 | __del__ = lambda self: None 541 | Line_Segment_swigregister = _visilibity.Line_Segment_swigregister 542 | Line_Segment_swigregister(Line_Segment) 543 | 544 | 545 | def distance(*args): 546 | return _visilibity.distance(*args) 547 | distance = _visilibity.distance 548 | 549 | def intersect(line_segment1, line_segment2, epsilon=0.0): 550 | return _visilibity.intersect(line_segment1, line_segment2, epsilon) 551 | intersect = _visilibity.intersect 552 | 553 | def intersect_proper(line_segment1, line_segment2, epsilon=0.0): 554 | return _visilibity.intersect_proper(line_segment1, line_segment2, epsilon) 555 | intersect_proper = _visilibity.intersect_proper 556 | class Angle(_object): 557 | __swig_setmethods__ = {} 558 | __setattr__ = lambda self, name, value: _swig_setattr(self, Angle, name, value) 559 | __swig_getmethods__ = {} 560 | __getattr__ = lambda self, name: _swig_getattr(self, Angle, name) 561 | __repr__ = _swig_repr 562 | 563 | def __init__(self, *args): 564 | this = _visilibity.new_Angle(*args) 565 | try: 566 | self.this.append(this) 567 | except __builtin__.Exception: 568 | self.this = this 569 | 570 | def get(self): 571 | return _visilibity.Angle_get(self) 572 | 573 | def set(self, data_temp): 574 | return _visilibity.Angle_set(self, data_temp) 575 | 576 | def set_to_2pi(self): 577 | return _visilibity.Angle_set_to_2pi(self) 578 | 579 | def randomize(self): 580 | return _visilibity.Angle_randomize(self) 581 | __swig_destroy__ = _visilibity.delete_Angle 582 | __del__ = lambda self: None 583 | Angle_swigregister = _visilibity.Angle_swigregister 584 | Angle_swigregister(Angle) 585 | 586 | 587 | def __add__(*args): 588 | return _visilibity.__add__(*args) 589 | __add__ = _visilibity.__add__ 590 | 591 | def __sub__(*args): 592 | return _visilibity.__sub__(*args) 593 | __sub__ = _visilibity.__sub__ 594 | 595 | def geodesic_distance(angle1, angle2): 596 | return _visilibity.geodesic_distance(angle1, angle2) 597 | geodesic_distance = _visilibity.geodesic_distance 598 | 599 | def geodesic_direction(angle1, angle2): 600 | return _visilibity.geodesic_direction(angle1, angle2) 601 | geodesic_direction = _visilibity.geodesic_direction 602 | class Polar_Point(Point): 603 | __swig_setmethods__ = {} 604 | for _s in [Point]: 605 | __swig_setmethods__.update(getattr(_s, '__swig_setmethods__', {})) 606 | __setattr__ = lambda self, name, value: _swig_setattr(self, Polar_Point, name, value) 607 | __swig_getmethods__ = {} 608 | for _s in [Point]: 609 | __swig_getmethods__.update(getattr(_s, '__swig_getmethods__', {})) 610 | __getattr__ = lambda self, name: _swig_getattr(self, Polar_Point, name) 611 | __repr__ = _swig_repr 612 | 613 | def __init__(self, *args): 614 | this = _visilibity.new_Polar_Point(*args) 615 | try: 616 | self.this.append(this) 617 | except __builtin__.Exception: 618 | self.this = this 619 | 620 | def polar_origin(self): 621 | return _visilibity.Polar_Point_polar_origin(self) 622 | 623 | def range(self): 624 | return _visilibity.Polar_Point_range(self) 625 | 626 | def bearing(self): 627 | return _visilibity.Polar_Point_bearing(self) 628 | 629 | def set_polar_origin(self, polar_origin_temp): 630 | return _visilibity.Polar_Point_set_polar_origin(self, polar_origin_temp) 631 | 632 | def set_x(self, x_temp): 633 | return _visilibity.Polar_Point_set_x(self, x_temp) 634 | 635 | def set_y(self, y_temp): 636 | return _visilibity.Polar_Point_set_y(self, y_temp) 637 | 638 | def set_range(self, range_temp): 639 | return _visilibity.Polar_Point_set_range(self, range_temp) 640 | 641 | def set_bearing(self, bearing_temp): 642 | return _visilibity.Polar_Point_set_bearing(self, bearing_temp) 643 | 644 | def set_bearing_to_2pi(self): 645 | return _visilibity.Polar_Point_set_bearing_to_2pi(self) 646 | __swig_destroy__ = _visilibity.delete_Polar_Point 647 | __del__ = lambda self: None 648 | Polar_Point_swigregister = _visilibity.Polar_Point_swigregister 649 | Polar_Point_swigregister(Polar_Point) 650 | 651 | 652 | def __gt__(*args): 653 | return _visilibity.__gt__(*args) 654 | __gt__ = _visilibity.__gt__ 655 | 656 | def __lt__(*args): 657 | return _visilibity.__lt__(*args) 658 | __lt__ = _visilibity.__lt__ 659 | 660 | def __ge__(*args): 661 | return _visilibity.__ge__(*args) 662 | __ge__ = _visilibity.__ge__ 663 | 664 | def __le__(*args): 665 | return _visilibity.__le__(*args) 666 | __le__ = _visilibity.__le__ 667 | class Ray(_object): 668 | __swig_setmethods__ = {} 669 | __setattr__ = lambda self, name, value: _swig_setattr(self, Ray, name, value) 670 | __swig_getmethods__ = {} 671 | __getattr__ = lambda self, name: _swig_getattr(self, Ray, name) 672 | __repr__ = _swig_repr 673 | 674 | def __init__(self, *args): 675 | this = _visilibity.new_Ray(*args) 676 | try: 677 | self.this.append(this) 678 | except __builtin__.Exception: 679 | self.this = this 680 | 681 | def base_point(self): 682 | return _visilibity.Ray_base_point(self) 683 | 684 | def bearing(self): 685 | return _visilibity.Ray_bearing(self) 686 | 687 | def set_base_point(self, point_temp): 688 | return _visilibity.Ray_set_base_point(self, point_temp) 689 | 690 | def set_bearing(self, angle_temp): 691 | return _visilibity.Ray_set_bearing(self, angle_temp) 692 | __swig_destroy__ = _visilibity.delete_Ray 693 | __del__ = lambda self: None 694 | Ray_swigregister = _visilibity.Ray_swigregister 695 | Ray_swigregister(Ray) 696 | 697 | 698 | def intersection(*args): 699 | return _visilibity.intersection(*args) 700 | intersection = _visilibity.intersection 701 | class Polyline(_object): 702 | __swig_setmethods__ = {} 703 | __setattr__ = lambda self, name, value: _swig_setattr(self, Polyline, name, value) 704 | __swig_getmethods__ = {} 705 | __getattr__ = lambda self, name: _swig_getattr(self, Polyline, name) 706 | __repr__ = _swig_repr 707 | 708 | def __init__(self, *args): 709 | this = _visilibity.new_Polyline(*args) 710 | try: 711 | self.this.append(this) 712 | except __builtin__.Exception: 713 | self.this = this 714 | 715 | def size(self): 716 | return _visilibity.Polyline_size(self) 717 | 718 | def length(self): 719 | return _visilibity.Polyline_length(self) 720 | 721 | def diameter(self): 722 | return _visilibity.Polyline_diameter(self) 723 | 724 | def bbox(self): 725 | return _visilibity.Polyline_bbox(self) 726 | 727 | def clear(self): 728 | return _visilibity.Polyline_clear(self) 729 | 730 | def push_back(self, point_temp): 731 | return _visilibity.Polyline_push_back(self, point_temp) 732 | 733 | def pop_back(self): 734 | return _visilibity.Polyline_pop_back(self) 735 | 736 | def set_vertices(self, vertices_temp): 737 | return _visilibity.Polyline_set_vertices(self, vertices_temp) 738 | 739 | def eliminate_redundant_vertices(self, epsilon=0.0): 740 | return _visilibity.Polyline_eliminate_redundant_vertices(self, epsilon) 741 | 742 | def reverse(self): 743 | return _visilibity.Polyline_reverse(self) 744 | 745 | def path(self): 746 | return _visilibity.Polyline_path(self) 747 | 748 | def append(self, polyline): 749 | return _visilibity.Polyline_append(self, polyline) 750 | __swig_destroy__ = _visilibity.delete_Polyline 751 | __del__ = lambda self: None 752 | Polyline_swigregister = _visilibity.Polyline_swigregister 753 | Polyline_swigregister(Polyline) 754 | 755 | class Polygon(_object): 756 | __swig_setmethods__ = {} 757 | __setattr__ = lambda self, name, value: _swig_setattr(self, Polygon, name, value) 758 | __swig_getmethods__ = {} 759 | __getattr__ = lambda self, name: _swig_getattr(self, Polygon, name) 760 | __repr__ = _swig_repr 761 | 762 | def __init__(self, *args): 763 | this = _visilibity.new_Polygon(*args) 764 | try: 765 | self.this.append(this) 766 | except __builtin__.Exception: 767 | self.this = this 768 | 769 | def n(self): 770 | return _visilibity.Polygon_n(self) 771 | 772 | def r(self): 773 | return _visilibity.Polygon_r(self) 774 | 775 | def is_simple(self, epsilon=0.0): 776 | return _visilibity.Polygon_is_simple(self, epsilon) 777 | 778 | def is_in_standard_form(self): 779 | return _visilibity.Polygon_is_in_standard_form(self) 780 | 781 | def boundary_length(self): 782 | return _visilibity.Polygon_boundary_length(self) 783 | 784 | def area(self): 785 | return _visilibity.Polygon_area(self) 786 | 787 | def centroid(self): 788 | return _visilibity.Polygon_centroid(self) 789 | 790 | def diameter(self): 791 | return _visilibity.Polygon_diameter(self) 792 | 793 | def bbox(self): 794 | return _visilibity.Polygon_bbox(self) 795 | 796 | def random_points(self, count, epsilon=0.0): 797 | return _visilibity.Polygon_random_points(self, count, epsilon) 798 | 799 | def write_to_file(self, *args): 800 | return _visilibity.Polygon_write_to_file(self, *args) 801 | 802 | def set_vertices(self, vertices_temp): 803 | return _visilibity.Polygon_set_vertices(self, vertices_temp) 804 | 805 | def push_back(self, vertex_temp): 806 | return _visilibity.Polygon_push_back(self, vertex_temp) 807 | 808 | def clear(self): 809 | return _visilibity.Polygon_clear(self) 810 | 811 | def enforce_standard_form(self): 812 | return _visilibity.Polygon_enforce_standard_form(self) 813 | 814 | def eliminate_redundant_vertices(self, epsilon=0.0): 815 | return _visilibity.Polygon_eliminate_redundant_vertices(self, epsilon) 816 | 817 | def reverse(self): 818 | return _visilibity.Polygon_reverse(self) 819 | 820 | def __getitem__(self, i): 821 | return _visilibity.Polygon___getitem__(self, i) 822 | __swig_destroy__ = _visilibity.delete_Polygon 823 | __del__ = lambda self: None 824 | Polygon_swigregister = _visilibity.Polygon_swigregister 825 | Polygon_swigregister(Polygon) 826 | 827 | 828 | def __eq__(*args): 829 | return _visilibity.__eq__(*args) 830 | __eq__ = _visilibity.__eq__ 831 | 832 | def __ne__(*args): 833 | return _visilibity.__ne__(*args) 834 | __ne__ = _visilibity.__ne__ 835 | 836 | def equivalent(*args): 837 | return _visilibity.equivalent(*args) 838 | equivalent = _visilibity.equivalent 839 | 840 | def boundary_distance(*args): 841 | return _visilibity.boundary_distance(*args) 842 | boundary_distance = _visilibity.boundary_distance 843 | class Environment(_object): 844 | __swig_setmethods__ = {} 845 | __setattr__ = lambda self, name, value: _swig_setattr(self, Environment, name, value) 846 | __swig_getmethods__ = {} 847 | __getattr__ = lambda self, name: _swig_getattr(self, Environment, name) 848 | __repr__ = _swig_repr 849 | 850 | def __init__(self, *args): 851 | this = _visilibity.new_Environment(*args) 852 | try: 853 | self.this.append(this) 854 | except __builtin__.Exception: 855 | self.this = this 856 | 857 | def h(self): 858 | return _visilibity.Environment_h(self) 859 | 860 | def n(self): 861 | return _visilibity.Environment_n(self) 862 | 863 | def r(self): 864 | return _visilibity.Environment_r(self) 865 | 866 | def is_in_standard_form(self): 867 | return _visilibity.Environment_is_in_standard_form(self) 868 | 869 | def is_valid(self, epsilon=0.0): 870 | return _visilibity.Environment_is_valid(self, epsilon) 871 | 872 | def boundary_length(self): 873 | return _visilibity.Environment_boundary_length(self) 874 | 875 | def area(self): 876 | return _visilibity.Environment_area(self) 877 | 878 | def diameter(self): 879 | return _visilibity.Environment_diameter(self) 880 | 881 | def bbox(self): 882 | return _visilibity.Environment_bbox(self) 883 | 884 | def random_points(self, count, epsilon=0.0): 885 | return _visilibity.Environment_random_points(self, count, epsilon) 886 | 887 | def shortest_path(self, *args): 888 | return _visilibity.Environment_shortest_path(self, *args) 889 | 890 | def compute_partition_cells(self, partition_inducing_segments, epsilon=0.0): 891 | return _visilibity.Environment_compute_partition_cells(self, partition_inducing_segments, epsilon) 892 | 893 | def write_to_file(self, *args): 894 | return _visilibity.Environment_write_to_file(self, *args) 895 | 896 | def __call__(self, *args): 897 | return _visilibity.Environment___call__(self, *args) 898 | 899 | def set_outer_boundary(self, polygon_temp): 900 | return _visilibity.Environment_set_outer_boundary(self, polygon_temp) 901 | 902 | def add_hole(self, polygon_temp): 903 | return _visilibity.Environment_add_hole(self, polygon_temp) 904 | 905 | def enforce_standard_form(self): 906 | return _visilibity.Environment_enforce_standard_form(self) 907 | 908 | def eliminate_redundant_vertices(self, epsilon=0.0): 909 | return _visilibity.Environment_eliminate_redundant_vertices(self, epsilon) 910 | 911 | def reverse_holes(self): 912 | return _visilibity.Environment_reverse_holes(self) 913 | __swig_destroy__ = _visilibity.delete_Environment 914 | __del__ = lambda self: None 915 | Environment_swigregister = _visilibity.Environment_swigregister 916 | Environment_swigregister(Environment) 917 | 918 | class Guards(_object): 919 | __swig_setmethods__ = {} 920 | __setattr__ = lambda self, name, value: _swig_setattr(self, Guards, name, value) 921 | __swig_getmethods__ = {} 922 | __getattr__ = lambda self, name: _swig_getattr(self, Guards, name) 923 | __repr__ = _swig_repr 924 | 925 | def __init__(self, *args): 926 | this = _visilibity.new_Guards(*args) 927 | try: 928 | self.this.append(this) 929 | except __builtin__.Exception: 930 | self.this = this 931 | 932 | def N(self): 933 | return _visilibity.Guards_N(self) 934 | 935 | def are_lex_ordered(self): 936 | return _visilibity.Guards_are_lex_ordered(self) 937 | 938 | def noncolocated(self, epsilon=0.0): 939 | return _visilibity.Guards_noncolocated(self, epsilon) 940 | 941 | def _in(self, *args): 942 | return _visilibity.Guards__in(self, *args) 943 | 944 | def diameter(self): 945 | return _visilibity.Guards_diameter(self) 946 | 947 | def bbox(self): 948 | return _visilibity.Guards_bbox(self) 949 | 950 | def write_to_file(self, *args): 951 | return _visilibity.Guards_write_to_file(self, *args) 952 | 953 | def push_back(self, point_temp): 954 | return _visilibity.Guards_push_back(self, point_temp) 955 | 956 | def set_positions(self, positions_temp): 957 | return _visilibity.Guards_set_positions(self, positions_temp) 958 | 959 | def enforce_lex_order(self): 960 | return _visilibity.Guards_enforce_lex_order(self) 961 | 962 | def reverse(self): 963 | return _visilibity.Guards_reverse(self) 964 | 965 | def snap_to_vertices_of(self, *args): 966 | return _visilibity.Guards_snap_to_vertices_of(self, *args) 967 | 968 | def snap_to_boundary_of(self, *args): 969 | return _visilibity.Guards_snap_to_boundary_of(self, *args) 970 | __swig_destroy__ = _visilibity.delete_Guards 971 | __del__ = lambda self: None 972 | Guards_swigregister = _visilibity.Guards_swigregister 973 | Guards_swigregister(Guards) 974 | 975 | class Visibility_Polygon(Polygon): 976 | __swig_setmethods__ = {} 977 | for _s in [Polygon]: 978 | __swig_setmethods__.update(getattr(_s, '__swig_setmethods__', {})) 979 | __setattr__ = lambda self, name, value: _swig_setattr(self, Visibility_Polygon, name, value) 980 | __swig_getmethods__ = {} 981 | for _s in [Polygon]: 982 | __swig_getmethods__.update(getattr(_s, '__swig_getmethods__', {})) 983 | __getattr__ = lambda self, name: _swig_getattr(self, Visibility_Polygon, name) 984 | __repr__ = _swig_repr 985 | 986 | def __init__(self, *args): 987 | this = _visilibity.new_Visibility_Polygon(*args) 988 | try: 989 | self.this.append(this) 990 | except __builtin__.Exception: 991 | self.this = this 992 | 993 | def observer(self): 994 | return _visilibity.Visibility_Polygon_observer(self) 995 | __swig_destroy__ = _visilibity.delete_Visibility_Polygon 996 | __del__ = lambda self: None 997 | Visibility_Polygon_swigregister = _visilibity.Visibility_Polygon_swigregister 998 | Visibility_Polygon_swigregister(Visibility_Polygon) 999 | 1000 | class Visibility_Graph(_object): 1001 | __swig_setmethods__ = {} 1002 | __setattr__ = lambda self, name, value: _swig_setattr(self, Visibility_Graph, name, value) 1003 | __swig_getmethods__ = {} 1004 | __getattr__ = lambda self, name: _swig_getattr(self, Visibility_Graph, name) 1005 | __repr__ = _swig_repr 1006 | 1007 | def __init__(self, *args): 1008 | this = _visilibity.new_Visibility_Graph(*args) 1009 | try: 1010 | self.this.append(this) 1011 | except __builtin__.Exception: 1012 | self.this = this 1013 | 1014 | def n(self): 1015 | return _visilibity.Visibility_Graph_n(self) 1016 | 1017 | def __call__(self, *args): 1018 | return _visilibity.Visibility_Graph___call__(self, *args) 1019 | __swig_destroy__ = _visilibity.delete_Visibility_Graph 1020 | __del__ = lambda self: None 1021 | Visibility_Graph_swigregister = _visilibity.Visibility_Graph_swigregister 1022 | Visibility_Graph_swigregister(Visibility_Graph) 1023 | 1024 | 1025 | def __lshift__(*args): 1026 | return _visilibity.__lshift__(*args) 1027 | __lshift__ = _visilibity.__lshift__ 1028 | # This file is compatible with both classic and new-style classes. 1029 | 1030 | 1031 | -------------------------------------------------------------------------------- /visilibity_test.py: -------------------------------------------------------------------------------- 1 | # PyVisiLibity: a Python binding of VisiLibity1 2 | # Copyright (C) 2018 Yu Cao < University of Southampton> Yu.Cao at soton.ac.uk 3 | # Originally by Ramiro C. of UNC, Argentina 4 | # 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU Lesser General Public License as published by 8 | # the Free Software Foundation; either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Lesser General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Lesser General Public License 17 | # along with this program; if not, write to the Free Software Foundation, 18 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 | 20 | 21 | from __future__ import print_function 22 | import visilibity as vis 23 | 24 | # Used to plot the example 25 | import matplotlib.pylab as p 26 | 27 | # Used in the create_cone function 28 | import math 29 | 30 | def testVisilibity(): 31 | 32 | # Define an epsilon value (should be != 0.0) 33 | epsilon = 0.0000001 34 | 35 | # Define the points which will be the outer boundary of the environment 36 | # Must be COUNTER-CLOCK-WISE(ccw) 37 | p1 = vis.Point(0,0) 38 | p2 = vis.Point(700,0) 39 | p3 = vis.Point(700,900) 40 | p4 = vis.Point(0,900) 41 | 42 | # Load the values of the outer boundary polygon in order to draw it later 43 | wall_x = [p1.x(), p2.x(), p3.x(), p4.x(), p1.x()] 44 | wall_y = [p1.y(), p2.y(), p3.y(), p4.y(), p1.y()] 45 | 46 | # Outer boundary polygon must be COUNTER-CLOCK-WISE(ccw) 47 | # Create the outer boundary polygon 48 | walls = vis.Polygon([p1, p2, p3, p4]) 49 | 50 | # Define the point of the "observer" 51 | observer = vis.Point(235,400) 52 | 53 | # Uncomment the following line in order to create a cone polygon 54 | #walls = create_cone((observer.x(), observer.y()), 500, 270, 30, quality= 3) 55 | 56 | # Walls should be in standard form 57 | print('Walls in standard form : ',walls.is_in_standard_form()) 58 | 59 | # Now we define some holes for our environment. The holes must be inside 60 | # our outer boundary polygon. A hole blocks the observer vision, it works as 61 | # an obstacle in his vision sensor. 62 | 63 | 64 | # We define some point for a hole. You can add more points in order to get 65 | # the shape you want. 66 | # The smalles point should be first 67 | p2 =vis.Point(100, 300) 68 | p3 =vis.Point(100, 500) 69 | p4 =vis.Point(150, 500) 70 | p1 =vis.Point(150, 300) 71 | 72 | # Load the values of the hole polygon in order to draw it later 73 | hole_x = [p1.x(), p2.x(), p3.x(), p4.x(),p1.x()] 74 | hole_y = [p1.y(), p2.y(), p3.y(), p4.y(),p1.y()] 75 | 76 | # Note: The point of a hole must be in CLOCK-WISE(cw) order. 77 | # Create the hole polygon 78 | hole = vis.Polygon([p2,p3,p4,p1]) 79 | 80 | # Check if the hole is in standard form 81 | print('Hole in standard form: ',hole.is_in_standard_form()) 82 | 83 | 84 | # Define another point of a hole polygon 85 | # Remember: the list of points must be CLOCK-WISE(cw) 86 | p1 =vis.Point(300, 300) 87 | p2 =vis.Point(300, 500) 88 | p3 =vis.Point(400, 550) 89 | p4 =vis.Point(400, 300) 90 | 91 | # Load the values of the hole polygon in order to draw it later 92 | hole1_x = [p1.x(), p2.x(), p3.x(), p4.x(),p1.x()] 93 | hole1_y = [p1.y(), p2.y(), p3.y(), p4.y(),p1.y()] 94 | 95 | # Create the hole polygon 96 | hole1 = vis.Polygon([p1,p2,p3,p4]) 97 | 98 | # Check if the hole is in standard form 99 | print('Hole in standard form: ',hole1.is_in_standard_form()) 100 | 101 | # Define another point of a hole polygon 102 | # Remember: the list of points must be CLOCK-WISE(cw) 103 | p2 =vis.Point(90, 700) 104 | p3 =vis.Point(250, 750) 105 | p4 =vis.Point(220, 600) 106 | p1 =vis.Point(150, 600) 107 | 108 | # Load the values of the hole polygon in order to draw it later 109 | hole2_x = [p1.x(), p2.x(), p3.x(), p4.x(),p1.x()] 110 | hole2_y = [p1.y(), p2.y(), p3.y(), p4.y(),p1.y()] 111 | 112 | # Create the hole polygon 113 | hole2 = vis.Polygon([p2,p3,p4,p1]) 114 | 115 | # Check if the hole is in standard form 116 | print('Hole in standard form: ',hole2.is_in_standard_form()) 117 | 118 | # Define another point of a hole polygon 119 | # Remember: the list of points must be CLOCK-WISE(cw) 120 | p1 =vis.Point(330, 700) 121 | p2 =vis.Point(330, 800) 122 | p3 =vis.Point(530, 850) 123 | p4 =vis.Point(530, 790) 124 | 125 | # Load the values of the hole polygon in order to draw it later 126 | hole3_x = [p1.x(), p2.x(), p3.x(), p4.x(),p1.x()] 127 | hole3_y = [p1.y(), p2.y(), p3.y(), p4.y(),p1.y()] 128 | 129 | # Create the hole polygon 130 | hole3 = vis.Polygon([p1,p2,p3,p4]) 131 | 132 | # Check if the hole is in standard form 133 | print('Hole in standard form: ',hole3.is_in_standard_form()) 134 | 135 | # Define another point of a hole polygon 136 | # Remember: the list of points must be CLOCK-WISE(cw) 137 | p1 =vis.Point(230, 50) 138 | p2 =vis.Point(250, 90) 139 | p3 =vis.Point(390, 90) 140 | p4 =vis.Point(390, 50) 141 | 142 | # Load the values of the hole polygon in order to draw it later 143 | hole4_x = [p1.x(), p2.x(), p3.x(), p4.x(),p1.x()] 144 | hole4_y = [p1.y(), p2.y(), p3.y(), p4.y(),p1.y()] 145 | 146 | # Create the hole polygon 147 | hole4 = vis.Polygon([p1,p2,p3,p4]) 148 | 149 | # Check if the hole is in standard form 150 | print('Hole in standard form: ',hole4.is_in_standard_form()) 151 | 152 | 153 | # Create environment, wall will be the outer boundary because 154 | # is the first polygon in the list. The other polygons will be holes 155 | env = vis.Environment([walls, hole,hole2, hole1, hole3, hole4]) 156 | 157 | 158 | # Check if the environment is valid 159 | print('Environment is valid : ',env.is_valid(epsilon)) 160 | 161 | 162 | # Define another point, could be used to check if the observer see it, to 163 | # check the shortest path from one point to the other, etc. 164 | end = vis.Point(330, 525) 165 | 166 | # Define another point that the 'observer' will see 167 | end_visible = vis.Point(415,45) 168 | 169 | # Necesary to generate the visibility polygon 170 | observer.snap_to_boundary_of(env, epsilon) 171 | observer.snap_to_vertices_of(env, epsilon) 172 | 173 | # Obtein the visibility polygon of the 'observer' in the environmente 174 | # previously define 175 | isovist = vis.Visibility_Polygon(observer, env, epsilon) 176 | 177 | # Uncomment the following line to obtein the visibility polygon 178 | # of 'end' in the environmente previously define 179 | #polygon_vis = vis.Visibility_Polygon(end, env, epsilon) 180 | 181 | # Obtein the shortest path from 'observer' to 'end' and 'end_visible' 182 | # in the environment previously define 183 | shortest_path = env.shortest_path(observer, end, epsilon) 184 | shortest_path1 = env.shortest_path(observer, end_visible, epsilon) 185 | 186 | # Print the length of the path 187 | print("Shortest Path length from observer to end: ", shortest_path.length()) 188 | print( "Shortest Path length from observer to end_visible: ", shortest_path1.length()) 189 | 190 | 191 | # Check if 'observer' can see 'end', i.e., check if 'end' point is in 192 | # the visibility polygon of 'observer' 193 | print( "Can observer see end? ", end._in(isovist, epsilon)) 194 | 195 | print( "Can observer see end_visible? ", end_visible._in(isovist, epsilon)) 196 | 197 | # Print the point of the visibility polygon of 'observer' and save them 198 | # in two arrays in order to draw the polygon later 199 | point_x , point_y = save_print(isovist) 200 | 201 | # Add the first point again because the function to draw, draw a line from 202 | # one point to the next one and to close the figure we need the last line 203 | # from the last point to the first one 204 | point_x.append(isovist[0].x()) 205 | point_y.append(isovist[0].y()) 206 | 207 | # Set the title 208 | p.title('VisiLibity Test') 209 | 210 | # Set the labels for the axis 211 | p.xlabel('X Position') 212 | p.ylabel('Y Position') 213 | 214 | # Plot the outer boundary with black color 215 | p.plot(wall_x, wall_y, 'black') 216 | 217 | # Plot the position of the observer with a green dot ('go') 218 | p.plot([observer.x()], [observer.y()], 'go') 219 | 220 | # Plot the position of 'end' with a green dot ('go') 221 | p.plot([end.x()],[end.y()], 'go') 222 | 223 | # Plot the position of 'end_visible' with a green dot ('go') 224 | p.plot([end_visible.x()],[end_visible.y()], 'go') 225 | 226 | # Plot the visibility polygon of 'observer' 227 | p.plot(point_x, point_y) 228 | 229 | # Plot the hole polygon with red color 230 | p.plot(hole_x, hole_y, 'r') 231 | 232 | # Plot the hole polygon with red color 233 | p.plot(hole1_x, hole1_y, 'r') 234 | 235 | # Plot the hole polygon with red color 236 | p.plot(hole2_x, hole2_y, 'r') 237 | 238 | # Plot the hole polygon with red color 239 | p.plot(hole3_x, hole3_y, 'r') 240 | 241 | # Plot the hole polygon with red color 242 | p.plot(hole4_x, hole4_y, 'r') 243 | 244 | # Example of a cone-shape polygon 245 | cone_point = vis.Point(440,420) 246 | cone = create_cone([cone_point.x(),cone_point.y()], 150, 0, 45, 3) 247 | cone_x, cone_y = save_print(cone) 248 | cone_x.append(cone_x[0]) 249 | cone_y.append(cone_y[0]) 250 | p.plot([cone_point.x()], [cone_point.y()], 'go') 251 | p.plot(cone_x, cone_y) 252 | 253 | # Show the plot 254 | p.show() 255 | 256 | 257 | def save_print(polygon): 258 | end_pos_x = [] 259 | end_pos_y = [] 260 | print ('Points of Polygon: ') 261 | for i in range(polygon.n()): 262 | x = polygon[i].x() 263 | y = polygon[i].y() 264 | 265 | end_pos_x.append(x) 266 | end_pos_y.append(y) 267 | 268 | print( x,y) 269 | 270 | return end_pos_x, end_pos_y 271 | 272 | 273 | # Desc: This function creates a cone-shape polygon. To do that it use 274 | # five inputs(point, radius, angle, opening, resolution). 275 | # 'point': is the vertex of the cone. 276 | # 'radius': is the longitude from 'point' to any point in the arc. 277 | # 'angle': is the direcction of the cone. 278 | # 'resolution': is the number of degrees one point and the next in the arc. 279 | # Return: The function returns a Polygon object with the shape of 280 | # a cone with the above characteristics. 281 | def create_cone(point, radio, angle, opening, resolution=1): 282 | 283 | # Define the list for the points of the cone-shape polygon 284 | p=[] 285 | 286 | # The fisrt point will be the vertex of the cone 287 | p.append(vis.Point(point[0], point[1])) 288 | 289 | # Define the start and end of the arc 290 | start = angle - opening 291 | end = angle + opening 292 | 293 | for i in range(start, end, resolution): 294 | 295 | # Convert start angle from degrees to radians 296 | rad = math.radians(i) 297 | 298 | # Calculate the off-set of the first point of the arc 299 | x = radio*math.cos(rad) 300 | y = radio*math.sin(rad) 301 | 302 | # Add the off-set to the vertex point 303 | new_x = point[0] + x 304 | new_y = point[1] + y 305 | 306 | # Add the first point of the arc to the list 307 | p.append( vis.Point(new_x, new_y) ) 308 | 309 | # Add the last point of the arc 310 | rad = math.radians(end) 311 | x = radio*math.cos(rad) 312 | y = radio*math.sin(rad) 313 | new_x = point[0] + x 314 | new_y = point[1] + y 315 | p.append( vis.Point(new_x, new_y) ) 316 | 317 | return vis.Polygon(p) 318 | 319 | if __name__ == "__main__": 320 | testVisilibity() 321 | --------------------------------------------------------------------------------