From 4b682cbf174447ec1f3e64e0d665a9b6c6718bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=A8=E6=A0=88=E5=B0=8F=E5=AD=A6=E7=94=9F?= <1518079521@qq.com> Date: Tue, 10 Oct 2023 16:52:54 +0800 Subject: [PATCH] uupdate admin --- admin/vendor/autoload.php | 25 + admin/vendor/composer/ClassLoader.php | 585 +++ admin/vendor/composer/InstalledVersions.php | 352 ++ admin/vendor/composer/LICENSE | 21 + admin/vendor/composer/autoload_classmap.php | 10 + admin/vendor/composer/autoload_namespaces.php | 9 + admin/vendor/composer/autoload_psr4.php | 10 + admin/vendor/composer/autoload_real.php | 38 + admin/vendor/composer/autoload_static.php | 36 + admin/vendor/composer/installed.json | 88 + admin/vendor/composer/installed.php | 32 + admin/vendor/composer/platform_check.php | 26 + .../mjaschen/phpgeo/.github/workflows/php.yml | 61 + admin/vendor/mjaschen/phpgeo/.gitignore | 11 + admin/vendor/mjaschen/phpgeo/.scrutinizer.yml | 9 + admin/vendor/mjaschen/phpgeo/.travis.yml | 50 + admin/vendor/mjaschen/phpgeo/CHANGELOG.md | 317 ++ .../vendor/mjaschen/phpgeo/CODE_OF_CONDUCT.md | 46 + admin/vendor/mjaschen/phpgeo/CONTRIBUTING.md | 17 + admin/vendor/mjaschen/phpgeo/LICENSE | 21 + admin/vendor/mjaschen/phpgeo/Makefile | 48 + admin/vendor/mjaschen/phpgeo/README.md | 273 ++ admin/vendor/mjaschen/phpgeo/composer.json | 77 + .../docs/#intersection-polyline-simple.dxf | 3408 +++++++++++++++++ .../mjaschen/phpgeo/docs/000_Introduction.md | 22 + .../mjaschen/phpgeo/docs/010_Installation.md | 24 + .../mjaschen/phpgeo/docs/015_Upgrading.md | 38 + .../mjaschen/phpgeo/docs/020_Development.md | 96 + .../docs/100_Geometries/110_Coordinate.md | 15 + .../phpgeo/docs/100_Geometries/120_Line.md | 170 + .../docs/100_Geometries/130_Polyline.md | 126 + .../phpgeo/docs/100_Geometries/140_Polygon.md | 167 + .../phpgeo/docs/100_Geometries/200_Bounds.md | 26 + .../docs/100_Geometries/300_Ellipsoid.md | 61 + .../docs/100_Geometries/bounds-factory.png | Bin 0 -> 76244 bytes .../phpgeo/docs/100_Geometries/index.md | 14 + .../310_Same_Point_Comparison.md | 30 + .../docs/300_Comparisons/320_Directions.md | 34 + .../docs/300_Comparisons/340_Intersections.md | 14 + .../410_Distance_and_Length.md | 121 + .../420_Bearing_and_Destination.md | 143 + .../400_Calculations/425_Cardinal_Distance.md | 70 + .../430_Perpendicular_Distance.md | 43 + .../435_Distance_Between_Point_and_Line.md | 46 + .../docs/400_Calculations/440_Geofence.md | 40 + .../400_Calculations/cardinal-distance.png | Bin 0 -> 10254 bytes .../phpgeo/docs/400_Calculations/index.md | 3 + .../perpendicular-distance.png | Bin 0 -> 13745 bytes .../point-to-line-distance.png | Bin 0 -> 22529 bytes .../510_Simplifying_a_Polyline_or_Polygon.md | 91 + .../index.md | 5 + .../simplify.png | Bin 0 -> 193887 bytes .../100_Coordinates.md | 125 + .../130_Polylines.md | 32 + .../600_Formatting_and_Output/140_Polygons.md | 34 + .../docs/600_Formatting_and_Output/index.md | 5 + .../110_Coordinates_Parser.md | 53 + .../docs/700_Parsing_and_Input/index.md | 7 + .../phpgeo/docs/900_Further_Reading.md | 6 + .../phpgeo/docs/BoundsFactory.afdesign | Bin 0 -> 16633 bytes .../phpgeo/docs/Cardinal_Distance.afdesign | Bin 0 -> 10492 bytes .../docs/Line_to_Point_Distance.afdesign | Bin 0 -> 12930 bytes .../docs/Perpendicular_Distance.afdesign | Bin 0 -> 13315 bytes admin/vendor/mjaschen/phpgeo/docs/config.json | 25 + .../docs/intersection-polyline-simple.dxf | 3400 ++++++++++++++++ admin/vendor/mjaschen/phpgeo/phpcs.xml.dist | 121 + admin/vendor/mjaschen/phpgeo/phpunit.xml | 14 + admin/vendor/mjaschen/phpgeo/psalm.xml | 13 + .../phpgeo/src/Bearing/BearingEllipsoidal.php | 256 ++ .../phpgeo/src/Bearing/BearingInterface.php | 48 + .../phpgeo/src/Bearing/BearingSpherical.php | 89 + .../src/Bearing/DirectVincentyBearing.php | 53 + .../src/Bearing/InverseVincentyBearing.php | 66 + admin/vendor/mjaschen/phpgeo/src/Bounds.php | 118 + .../CardinalDirection/CardinalDirection.php | 133 + .../CardinalDirectionDistances.php | 133 + .../CardinalDirectionDistancesCalculator.php | 78 + .../vendor/mjaschen/phpgeo/src/Coordinate.php | 176 + .../phpgeo/src/Direction/Direction.php | 30 + .../phpgeo/src/Distance/DistanceInterface.php | 23 + .../phpgeo/src/Distance/Haversine.php | 53 + .../mjaschen/phpgeo/src/Distance/Vincenty.php | 111 + .../vendor/mjaschen/phpgeo/src/Ellipsoid.php | 128 + .../BearingNotAvailableException.php | 9 + .../Exception/InvalidDistanceException.php | 9 + .../Exception/InvalidGeometryException.php | 9 + .../src/Exception/InvalidPolygonException.php | 9 + .../src/Exception/NotConvergingException.php | 9 + .../NotMatchingEllipsoidException.php | 9 + .../phpgeo/src/Factory/BoundsFactory.php | 36 + .../phpgeo/src/Factory/CoordinateFactory.php | 163 + .../src/Factory/GeometryFactoryInterface.php | 22 + .../phpgeo/src/Formatter/Coordinate/DMS.php | 216 ++ .../Formatter/Coordinate/DecimalDegrees.php | 64 + .../Formatter/Coordinate/DecimalMinutes.php | 252 ++ .../Coordinate/FormatterInterface.php | 22 + .../src/Formatter/Coordinate/GeoJSON.php | 33 + .../Formatter/Polygon/FormatterInterface.php | 23 + .../phpgeo/src/Formatter/Polygon/GeoJSON.php | 45 + .../Formatter/Polyline/FormatterInterface.php | 22 + .../phpgeo/src/Formatter/Polyline/GeoJSON.php | 36 + .../mjaschen/phpgeo/src/GeometryInterface.php | 15 + .../mjaschen/phpgeo/src/GetBoundsTrait.php | 43 + .../phpgeo/src/Intersection/Intersection.php | 90 + admin/vendor/mjaschen/phpgeo/src/Line.php | 280 ++ admin/vendor/mjaschen/phpgeo/src/Polygon.php | 260 ++ admin/vendor/mjaschen/phpgeo/src/Polyline.php | 197 + .../Processor/Polyline/SimplifyBearing.php | 120 + .../Polyline/SimplifyDouglasPeucker.php | 135 + .../Processor/Polyline/SimplifyInterface.php | 24 + .../mjaschen/phpgeo/src/Utility/Cartesian.php | 73 + .../src/Utility/PerpendicularDistance.php | 82 + .../src/Utility/PointToLineDistance.php | 88 + .../Bearing/BearingEllipsoidalTest.php | 212 + .../Location/Bearing/BearingSphericalTest.php | 203 + .../phpgeo/tests/Location/BoundsTest.php | 88 + ...rdinalDirectionDistancesCalculatorTest.php | 120 + .../CardinalDirectionDistancesTest.php | 77 + .../CardinalDirectionTest.php | 111 + .../phpgeo/tests/Location/CoordinateTest.php | 134 + .../Location/Direction/DirectionTest.php | 41 + .../tests/Location/Distance/HaversineTest.php | 89 + .../tests/Location/Distance/VincentyTest.php | 92 + .../Location/Factory/BoundsFactoryTest.php | 95 + .../Factory/CoordinateFactoryTest.php | 411 ++ .../Location/Formatter/Coordinate/DMSTest.php | 96 + .../Coordinate/DecimalDegreesTest.php | 57 + .../Coordinate/DecimalMinutesTest.php | 113 + .../Formatter/Coordinate/GeoJSONTest.php | 52 + .../Formatter/Polygon/GeoJSONTest.php | 60 + .../Formatter/Polyline/GeoJSONTest.php | 46 + .../Intersection/IntersectionTest.php | 210 + .../phpgeo/tests/Location/LineTest.php | 152 + .../phpgeo/tests/Location/PolygonTest.php | 569 +++ .../phpgeo/tests/Location/PolylineTest.php | 159 + .../Polyline/SimplifyBearingTest.php | 93 + .../Polyline/SimplifyDouglasPeuckerTest.php | 143 + .../tests/Location/Utility/CartesianTest.php | 39 + .../PointToLineDistanceTestHaversineTest.php | 157 + .../PointToLineDistanceTestVincentyTest.php | 158 + .../Regression/Github/15/Issue15Test.php | 94 + .../Regression/Github/18/Issue18Test.php | 23 + .../Regression/Github/42/Issue42Test.php | 23 + .../Regression/Github/68/Issue68Test.php | 22 + .../Regression/Github/92/Issue92Test.php | 68 + .../mjaschen/phpgeo/tests/bootstrap.php | 3 + 146 files changed, 18704 insertions(+) create mode 100644 admin/vendor/autoload.php create mode 100644 admin/vendor/composer/ClassLoader.php create mode 100644 admin/vendor/composer/InstalledVersions.php create mode 100644 admin/vendor/composer/LICENSE create mode 100644 admin/vendor/composer/autoload_classmap.php create mode 100644 admin/vendor/composer/autoload_namespaces.php create mode 100644 admin/vendor/composer/autoload_psr4.php create mode 100644 admin/vendor/composer/autoload_real.php create mode 100644 admin/vendor/composer/autoload_static.php create mode 100644 admin/vendor/composer/installed.json create mode 100644 admin/vendor/composer/installed.php create mode 100644 admin/vendor/composer/platform_check.php create mode 100644 admin/vendor/mjaschen/phpgeo/.github/workflows/php.yml create mode 100644 admin/vendor/mjaschen/phpgeo/.gitignore create mode 100644 admin/vendor/mjaschen/phpgeo/.scrutinizer.yml create mode 100644 admin/vendor/mjaschen/phpgeo/.travis.yml create mode 100644 admin/vendor/mjaschen/phpgeo/CHANGELOG.md create mode 100644 admin/vendor/mjaschen/phpgeo/CODE_OF_CONDUCT.md create mode 100644 admin/vendor/mjaschen/phpgeo/CONTRIBUTING.md create mode 100644 admin/vendor/mjaschen/phpgeo/LICENSE create mode 100644 admin/vendor/mjaschen/phpgeo/Makefile create mode 100644 admin/vendor/mjaschen/phpgeo/README.md create mode 100644 admin/vendor/mjaschen/phpgeo/composer.json create mode 100644 admin/vendor/mjaschen/phpgeo/docs/#intersection-polyline-simple.dxf create mode 100644 admin/vendor/mjaschen/phpgeo/docs/000_Introduction.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/010_Installation.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/015_Upgrading.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/020_Development.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/110_Coordinate.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/120_Line.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/130_Polyline.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/140_Polygon.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/200_Bounds.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/300_Ellipsoid.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/bounds-factory.png create mode 100644 admin/vendor/mjaschen/phpgeo/docs/100_Geometries/index.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/310_Same_Point_Comparison.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/320_Directions.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/340_Intersections.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/410_Distance_and_Length.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/420_Bearing_and_Destination.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/425_Cardinal_Distance.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/430_Perpendicular_Distance.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/435_Distance_Between_Point_and_Line.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/440_Geofence.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/cardinal-distance.png create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/index.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/perpendicular-distance.png create mode 100644 admin/vendor/mjaschen/phpgeo/docs/400_Calculations/point-to-line-distance.png create mode 100644 admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/510_Simplifying_a_Polyline_or_Polygon.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/index.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/simplify.png create mode 100644 admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/100_Coordinates.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/130_Polylines.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/140_Polygons.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/index.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/110_Coordinates_Parser.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/index.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/900_Further_Reading.md create mode 100644 admin/vendor/mjaschen/phpgeo/docs/BoundsFactory.afdesign create mode 100644 admin/vendor/mjaschen/phpgeo/docs/Cardinal_Distance.afdesign create mode 100644 admin/vendor/mjaschen/phpgeo/docs/Line_to_Point_Distance.afdesign create mode 100644 admin/vendor/mjaschen/phpgeo/docs/Perpendicular_Distance.afdesign create mode 100644 admin/vendor/mjaschen/phpgeo/docs/config.json create mode 100644 admin/vendor/mjaschen/phpgeo/docs/intersection-polyline-simple.dxf create mode 100644 admin/vendor/mjaschen/phpgeo/phpcs.xml.dist create mode 100644 admin/vendor/mjaschen/phpgeo/phpunit.xml create mode 100644 admin/vendor/mjaschen/phpgeo/psalm.xml create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bearing/BearingEllipsoidal.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bearing/BearingInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bearing/BearingSpherical.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bearing/DirectVincentyBearing.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bearing/InverseVincentyBearing.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Bounds.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirection.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistances.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistancesCalculator.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Coordinate.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Direction/Direction.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Distance/DistanceInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Distance/Haversine.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Distance/Vincenty.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Ellipsoid.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/BearingNotAvailableException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/InvalidDistanceException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/InvalidGeometryException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/InvalidPolygonException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/NotConvergingException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Exception/NotMatchingEllipsoidException.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Factory/BoundsFactory.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Factory/CoordinateFactory.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Factory/GeometryFactoryInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DMS.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalDegrees.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalMinutes.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/FormatterInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/GeoJSON.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/FormatterInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/GeoJSON.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/FormatterInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/GeoJSON.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/GeometryInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/GetBoundsTrait.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Intersection/Intersection.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Line.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Polygon.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Polyline.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyBearing.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyDouglasPeucker.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyInterface.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Utility/Cartesian.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Utility/PerpendicularDistance.php create mode 100644 admin/vendor/mjaschen/phpgeo/src/Utility/PointToLineDistance.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingEllipsoidalTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingSphericalTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/BoundsTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesCalculatorTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/CoordinateTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Direction/DirectionTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Distance/HaversineTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Distance/VincentyTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Factory/BoundsFactoryTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Factory/CoordinateFactoryTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DMSTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalDegreesTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalMinutesTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/GeoJSONTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polygon/GeoJSONTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polyline/GeoJSONTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Intersection/IntersectionTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/LineTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/PolygonTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/PolylineTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyBearingTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyDouglasPeuckerTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Utility/CartesianTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestHaversineTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestVincentyTest.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Regression/Github/15/Issue15Test.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Regression/Github/18/Issue18Test.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Regression/Github/42/Issue42Test.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Regression/Github/68/Issue68Test.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/Regression/Github/92/Issue92Test.php create mode 100644 admin/vendor/mjaschen/phpgeo/tests/bootstrap.php diff --git a/admin/vendor/autoload.php b/admin/vendor/autoload.php new file mode 100644 index 000000000..5cfb7cd31 --- /dev/null +++ b/admin/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var ?string */ + private $vendorDir; + + // PSR-4 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array[] + * @psalm-var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * @var array[] + * @psalm-var array> + */ + private $prefixesPsr0 = array(); + /** + * @var array[] + * @psalm-var array + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var string[] + * @psalm-var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var bool[] + * @psalm-var array + */ + private $missingClasses = array(); + + /** @var ?string */ + private $apcuPrefix; + + /** + * @var self[] + */ + private static $registeredLoaders = array(); + + /** + * @param ?string $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return string[] + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array[] + * @psalm-return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return array[] + * @psalm-return array + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return string[] Array of classname => path + * @psalm-return array + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param string[] $classMap Class to filename map + * @psalm-param array $classMap + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param string[]|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param string[]|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders indexed by their corresponding vendor directories. + * + * @return self[] + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/admin/vendor/composer/InstalledVersions.php b/admin/vendor/composer/InstalledVersions.php new file mode 100644 index 000000000..c6b54af7b --- /dev/null +++ b/admin/vendor/composer/InstalledVersions.php @@ -0,0 +1,352 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints($constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = require __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + $installed[] = self::$installed; + + return $installed; + } +} diff --git a/admin/vendor/composer/LICENSE b/admin/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/admin/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/admin/vendor/composer/autoload_classmap.php b/admin/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..0fb0a2c19 --- /dev/null +++ b/admin/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/admin/vendor/composer/autoload_namespaces.php b/admin/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..15a2ff3ad --- /dev/null +++ b/admin/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/mjaschen/phpgeo/src'), +); diff --git a/admin/vendor/composer/autoload_real.php b/admin/vendor/composer/autoload_real.php new file mode 100644 index 000000000..596da34e5 --- /dev/null +++ b/admin/vendor/composer/autoload_real.php @@ -0,0 +1,38 @@ +register(true); + + return $loader; + } +} diff --git a/admin/vendor/composer/autoload_static.php b/admin/vendor/composer/autoload_static.php new file mode 100644 index 000000000..6d5f9316a --- /dev/null +++ b/admin/vendor/composer/autoload_static.php @@ -0,0 +1,36 @@ + + array ( + 'Location\\' => 9, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Location\\' => + array ( + 0 => __DIR__ . '/..' . '/mjaschen/phpgeo/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitf5da4e3fca64ccd39e0027088099d184::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitf5da4e3fca64ccd39e0027088099d184::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitf5da4e3fca64ccd39e0027088099d184::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/admin/vendor/composer/installed.json b/admin/vendor/composer/installed.json new file mode 100644 index 000000000..335dddbe2 --- /dev/null +++ b/admin/vendor/composer/installed.json @@ -0,0 +1,88 @@ +{ + "packages": [ + { + "name": "mjaschen/phpgeo", + "version": "4.2.0", + "version_normalized": "4.2.0.0", + "source": { + "type": "git", + "url": "https://github.com/mjaschen/phpgeo.git", + "reference": "b2e593cf1e9aceea36510158ddb80c7395a80d5a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mjaschen/phpgeo/zipball/b2e593cf1e9aceea36510158ddb80c7395a80d5a", + "reference": "b2e593cf1e9aceea36510158ddb80c7395a80d5a", + "shasum": "", + "mirrors": [ + { + "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.6", + "vimeo/psalm": "^4.13" + }, + "time": "2022-07-25T08:36:36+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Location\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marcus Jaschen", + "email": "mjaschen@gmail.com", + "homepage": "https://www.marcusjaschen.de/" + } + ], + "description": "Simple Yet Powerful Geo Library", + "homepage": "https://phpgeo.marcusjaschen.de/", + "keywords": [ + "Polygon", + "area", + "bearing", + "bounds", + "calculation", + "coordinate", + "distance", + "earth", + "ellipsoid", + "geo", + "geofence", + "gis", + "gps", + "haversine", + "length", + "perpendicular", + "point", + "polyline", + "projection", + "simplify", + "track", + "vincenty" + ], + "support": { + "docs": "https://phpgeo.marcusjaschen.de/Installation.html", + "email": "mjaschen@gmail.com", + "issues": "https://github.com/mjaschen/phpgeo/issues", + "source": "https://github.com/mjaschen/phpgeo/tree/4.2.0" + }, + "install-path": "../mjaschen/phpgeo" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/admin/vendor/composer/installed.php b/admin/vendor/composer/installed.php new file mode 100644 index 000000000..ff6ef8652 --- /dev/null +++ b/admin/vendor/composer/installed.php @@ -0,0 +1,32 @@ + array( + 'name' => '__root__', + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => '0e6af7d100b3d33b511309de65f355528845c27f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-master', + 'version' => 'dev-master', + 'reference' => '0e6af7d100b3d33b511309de65f355528845c27f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'mjaschen/phpgeo' => array( + 'pretty_version' => '4.2.0', + 'version' => '4.2.0.0', + 'reference' => 'b2e593cf1e9aceea36510158ddb80c7395a80d5a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../mjaschen/phpgeo', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/admin/vendor/composer/platform_check.php b/admin/vendor/composer/platform_check.php new file mode 100644 index 000000000..92370c5a0 --- /dev/null +++ b/admin/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 70300)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/admin/vendor/mjaschen/phpgeo/.github/workflows/php.yml b/admin/vendor/mjaschen/phpgeo/.github/workflows/php.yml new file mode 100644 index 000000000..a1d14e422 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/.github/workflows/php.yml @@ -0,0 +1,61 @@ +name: phpgeo Tests + +on: + push: + branches: + - "**" + pull_request: + branches: + - master + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: + - "7.3" + - "7.4" + - "8.0" + - "8.1" + + name: "phpgeo build - PHP ${{ matrix.php-versions }}" + + steps: + - uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: xdebug + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v2 + with: + path: vendor + key: ${{ runner.os }}-php-${{ matrix.php-versions }}-${{ hashFiles('composer.json') }} + restore-keys: | + ${{ runner.os }}-php-${{ matrix.php-versions }}- + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Lint PHP Sources + run: composer run-script ci:lint + + - name: PHP Code Sniffer + run: composer run-script ci:sniff + + - name: Static Analysis + run: composer run-script ci:psalm + + - name: Unit Tests + run: composer run-script ci:tests diff --git a/admin/vendor/mjaschen/phpgeo/.gitignore b/admin/vendor/mjaschen/phpgeo/.gitignore new file mode 100644 index 000000000..577f1626e --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/.gitignore @@ -0,0 +1,11 @@ +.DS_Store +*~ +/.idea/ +/composer.lock +/vendor/ +/docs/phpgeo.html +/docs/coverage/ +/docs/phpdox/ +/tools/ +/build/ +.phpunit.result.cache diff --git a/admin/vendor/mjaschen/phpgeo/.scrutinizer.yml b/admin/vendor/mjaschen/phpgeo/.scrutinizer.yml new file mode 100644 index 000000000..27dc67dcc --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/.scrutinizer.yml @@ -0,0 +1,9 @@ +filter: + paths: ["src/*"] +tools: + php_code_coverage: true + php_sim: true + php_mess_detector: true + php_pdepend: true + php_analyzer: true + php_cpd: false diff --git a/admin/vendor/mjaschen/phpgeo/.travis.yml b/admin/vendor/mjaschen/phpgeo/.travis.yml new file mode 100644 index 000000000..1836d1bad --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/.travis.yml @@ -0,0 +1,50 @@ +os: linux +dist: xenial +language: php + +php: + - "7.4" + - "7.3" + - "7.2" + +cache: + directories: + - vendor + - $HOME/.composer/cache + +env: + jobs: + - DEPENDENCIES=latest + - DEPENDENCIES=oldest + +install: +- > + if [ "$DEPENDENCIES" = "latest" ]; then + echo "Installing the latest dependencies"; + composer update --with-dependencies --prefer-stable --prefer-dist + else + echo "Installing the lowest dependencies"; + composer update --with-dependencies --prefer-stable --prefer-dist --prefer-lowest + fi; + composer show; + +script: +- > + echo; + echo "Validating the composer.json"; + composer ci:composer-validate; + +- > + echo; + echo "Linting all PHP files"; + composer ci:lint; + +- > + echo; + echo "Running the Psalm static analyzer"; + composer ci:psalm; + +- > + echo; + echo "Running the PHPUnit tests"; + composer ci:tests; diff --git a/admin/vendor/mjaschen/phpgeo/CHANGELOG.md b/admin/vendor/mjaschen/phpgeo/CHANGELOG.md new file mode 100644 index 000000000..613aa6a29 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/CHANGELOG.md @@ -0,0 +1,317 @@ +# Change Log + +All notable changes to `mjaschen/phpgeo` will be documented in this file. +Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. + +## Unreleased/Upcoming + +### Added + +- `GeometryInterface` provides two new methods: `getBounds()` and `getSegments()` + +### Removed + +- Support for PHP 7.3 +- `setPoint1()` and `setPoint2()` methods from `Line` +- `setSeparator()`, `useCardinalLetters()` and `setUnits()` methods from `DMS` + +## [4.2.0] - Current Version, 2022-07-25 + +## Changed + +- point-to-line distance is calculated iteratively now, fixes #92 +- improved intersection checking for polygon/polygon + +## [4.1.0] - 2022-06-03 + +This release has no breaking changes. + +Thanks, @nilshoerrmann, for contributing! + +### Added + +- method `Bounds::getAsPolygon()` which returns a polygon containing the four nodes of the Bounds instance +- methods `Bounds::getNorthEast()` and `Bounds::getSouthWest()` +- new public methods: `CardinalDirection::isStrictlyNorth()`, `CardinalDirection::isStrictlyEast()`, `CardinalDirection::isStrictlySouth()` and `CardinalDirection::isStrictlyWest()` +- new class `Direction` for checking if one point is north, eat, south or west from another point +- new Class `Intersection` for checking if two geometries intersect each other + +## [4.0.0] - 2021-11-29 + +### Changed + +- drop support for PHP 7.2 **breaking change** +- add support for PHP 8.1 +- add deprecations for setter methods in `DMS` and `Line` classes + +## [3.2.1] - 2021-03-04 + +### Fixed + +- Division by zero in `SimplifyBearing` if two consecutive points share the same location, fixes #79. + +## [3.2.0] - 2020-10-09 + +### Added + +- Calculation of [Cardinal Distances](https://phpgeo.marcusjaschen.de/Calculations/Cardinal_Distance.html) between two points. Thanks @LeoVie! + +### Changed + +- change `static` to `self` to prevent accidentally calling the constructor with wrong arguments in child classes (`Ellipsoid`, `Line`, `Polygon`, `Polyline`) + +## [3.1.0] - 2020-07-24 + +### Added + +- Simplifying polygons is now supported as well, see `simplifyGeometry()` methods in `SimplifyBearing` and `SimplifyDouglasPeucker` classes (fixes #69). + +## [3.0.1] - 2020-05-18 + +### Fixed + +- \#68 `CoordinateFactory` emitted a warning if a coordindates string without arc seconds was passed to the `fromString()` method + +## [3.0.0] - 2020-02-07 + +### Changed + +- *phpgeo* requires PHP >= 7.2 now +- **backwards compatibility breaking:** fix double space in Ellipsoid Name `World␣Geodetic␣System␣␣1984` → `World␣Geodetic␣System␣1984` (#49) +- updated tests for PHPUnit 8 + +### Added + +- class constant visibiliy modifiers + +### Removed + +- support for PHP 7.0 and PHP 7.1 from Travis CI config + +## [2.6.0] - 2020-02-05 + +### Added + +- method `getIntermediatePoint()` to the `Line` class which calculates an intermediate point on a line by following the Great Circle between the two line ends and dividing the line by the given fraction (0.0 ... 1.0) + +## [2.5.0] - 2020-02-04 + +### Added + +- method `getMidpoint()` to the `Line` class which calculates the midpoint of a line by following the Great Circle between the two line ends and dividing the line into two halves. +- utility class `Cartesian` which abstracts three-dimensional cartesian coordinates *x*, *y*, and *z* + +## [2.4.1] - 2020-01-29 + +### Changed + +- access modifier for the `tolerance` attribute is now protected (`SimplifyDouglasPeucker`) + +## [2.4.0] - 2020-01-27 + +### Added + +- `BoundsFactory` to create a bounds instance for a center point and a given distance to the bounds' corners. Thanks @sdennler! + +## [2.3.1] - 2019-12-21 + +### Fixed + +- improve precision in `PointToLineDistance` + +## [2.3.0] - 2019-12-19 + +### Added + +- `PointToLineDistance` calculates the smallest distance between a point and a line + +## [2.2.0] - 2019-11-25 + +### Added + +- `hasSameLocation()` checks if two points share the same location (optionally within a distance which defaults to 0.001 m = 1 mm) +- `addUniquePoint` adds unique points to a polyline (i.e., points that doesn't already exist in that polyline) +- `getAveragePoint()` returns the average value of latitude and longitude values for a polyline + +### Fixed + +- wrongly placed parenthesis in `Polygon::contains()` + +## [2.1.0] - 2019-03-22 + +### Added + +- The bounds for a `Polyline` can now be retrieved in form of a `Bound` object. + +### Changed + +- The auto-loader is now PSR-4 compatible; directory structure was flattened by one level. + +## [2.0.5] - 2019-02-27 + +### Changed + +- improvements to the Douglas-Peucker processor. Thanks @iamskey! + +## [2.0.3] - 2018-07-19 + +### Fixed + +- Links to documentation in README. Thanks @JonathanMH + +### Changed + +- better floating point number comparisons in `Vincenty` +- add exception message in `Vincenty` +- type-cast regexp matches before doing calculations in `CoordinateFactory` + +## [2.0.2] - 2018-03-27 + +### Added + +- Information on how to run checks and tests for developers in the README. + +### Changed + +- Updated internal stuff like type and return hints after running a static analysis. +- Updated some PHPDoc blocks after running a static analysis. + +### Fixed + +- Wrongly typed return value in `BearingEllipsoidal::inverseVincenty()`. + +## [2.0.1] - 2018-02-16 + +### Added + +- new supported format for coordinates parser. Thanks to @petrknap + +## [2.0.0] - 2017-09-27 + +### Changed + +* License: *phpgeo* is now distributed under the MIT license +* phpgeo requires at least PHP 7.0 + +### Removed + +* deprecated class `Simplify` was removed; alternatives: `SimplifyBearing` or `SimplifyDouglasPeucker` +* PHP versions 5.4, 5.5, and 5.6 are no longer supported + +## [1.3.8] - 2017-07-05 + +### Fixed + +* Area calculation for polygons works now. Thanks to @felixveysseyre + +## [1.3.7] - 2017-07-01 + +### Fixed + +* GeoJSON output for polygon is now compliant with RFC 7946. Thanks to @arsonik + +## [1.3.5] - 2016-08-19 + +### Added + +* add method for calculating the final bearing for a `Line` object + +## [1.3.3] - 2016-08-16 + +### Fixed + +* bugifx for a division-by-zero error which occurred when symplifying a polyline + with the Douglas-Peucker algorithm. + +## [1.3.2] - 2016-03-26 + +### Added + +* add an utility class to calculate the perpendicular distance between a point + and a line; [documentation](https://phpgeo.marcusjaschen.de/#_perpendicular_distance) + +## [1.3.1] - 2016-03-26 + +### Added + +* add method to calculate the bearing of a `Line` instance (point 1 -> point 2) + +## [1.3.0] - 2016-03-26 + +### Added + +* A new `SimplifyInterface` was introduced and is implemented in two classes: + `SimplifyDouglasPeucker` and `SimplifyBearing` +* Added documentation + +### Deprecated + +* The `Simplify` processor class is now deprecated and will be removed in the + 2.0 release. + +## [1.2.1] - 2016-03-15 + +### Added + +* Added functionality to change the direction of Polygon instances +* Added documentation + +## [1.2.0] - 2016-03-14 + +### Added + +* Added geofence check for arbitrary geometry objects +* Extended and updated documentation + +## [1.1.1] - 2016-03-13 + +### Added + +* Added formatter for "Decimal Minutes" format, e.g. `43° 37.386' N, 070° 12.472' W` +* Added documentation for the new formatter + +## [1.1.0] - 2016-03-12 + +### Added + +* Added calculation of the bearing angle between two points (initial and final bearing) +* Added calculation of the destination point for a given starting point, the bearing angle, and the distance +* Support for spherical and ellipsoidal algorithms for the described bearing calculations +* Added documentation for the bearing calculations + +## [1.0.4] - 2016-03-11 + +### Added + +* Added functionality to change the direction of Line/Polyline instances +* Added documentation + +## [1.0.3] - 2016-03-10 + +### Added + +* Added documentation sources in mkdocs format. Documentation is now available online at http://phpgeo.marcusjaschen.de/ + +## [1.0.2] - 2016-03-04 + +### Changed + +* several optimizations in control structures + +## [1.0.0] - 2016-02-11 + +### Added + +* Added license information. *phpgeo* is now licensed under the GPL 3. (see issue [#8](https://github.com/mjaschen/phpgeo/issues/8)) + +## [0.4.0] - 2015-10-29 + +### Deprecated + +* removed support for PHP 5.3; introduced short array syntax + +## [0.3.0] - 2015-10-29 + +### Added + +* added the new Polyline class (thanks [@paulvl](https://github.com/paulvl)) diff --git a/admin/vendor/mjaschen/phpgeo/CODE_OF_CONDUCT.md b/admin/vendor/mjaschen/phpgeo/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..2f26c6c53 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mjaschen@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/admin/vendor/mjaschen/phpgeo/CONTRIBUTING.md b/admin/vendor/mjaschen/phpgeo/CONTRIBUTING.md new file mode 100644 index 000000000..df7b8bd68 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/CONTRIBUTING.md @@ -0,0 +1,17 @@ +# Contributing to phpgeo + +Note: It's a good idea to [open an issue](https://github.com/mjaschen/phpgeo/issues) +for bugs or feature proposals first. + +The contribution workflow is described as follows: + +1. Fork phpgeo, clone repository (`git clone git@github.com:yourname/phpgeo.git`) +2. Checkout your feature or bug-fix branch (e. g. `git checkout -b fix-random-bug`) +3. Install dependencies: `composer install` +4. Add tests for your changes +5. Make your changes +6. Run the tests (`composer ci`) +7. Iterate through steps 3 to 5 until all tests pass. +8. Commit your changes (`git add -A -- . && git commit`) +9. Push to your fork (`git push --set-upstream origin fix-random-bug`) +10. Create a pull request from your feature or bug-fix branch to phpgeo's "master" branch diff --git a/admin/vendor/mjaschen/phpgeo/LICENSE b/admin/vendor/mjaschen/phpgeo/LICENSE new file mode 100644 index 000000000..1fa7b6180 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright 2017 Marcus Jaschen, https://www.marcusjaschen.de/ + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/admin/vendor/mjaschen/phpgeo/Makefile b/admin/vendor/mjaschen/phpgeo/Makefile new file mode 100644 index 000000000..08f852f2a --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/Makefile @@ -0,0 +1,48 @@ +UPLOAD_HOST=phpgeo.marcusjaschen.de +UPLOAD_PATH=phpgeo.marcusjaschen.de + +PHP ?= php + +.PHONY: docs +docs: daux + +.PHONY: daux +daux: + rm -Rf build/daux + mkdir -p build/daux + docker run --rm -v "$(PWD)":/src -w /src daux/daux.io daux generate -d build/daux + +.PHONY: clean +clean: + rm -Rf build + +.PHONY: upload_docs +upload_docs: docs + rsync --recursive --delete build/daux/ $(UPLOAD_HOST):$(UPLOAD_PATH)/ + +.PHONY: ci +ci: lint coding-standards composer-validate sniff static-analysis-psalm unit-tests + +.PHONY: coding-standards +coding-standards: sniff + +.PHONY: composer-validate +composer-validate: + composer validate --no-check-publish + +.PHONY: lint +lint: + $(PHP) ./vendor/bin/parallel-lint src + +.PHONY: sniff +sniff: + # the `-` prefix ignores the exit status of the command + -$(PHP) ./vendor/bin/phpcs --standard=codesniffer_rules.xml src + +.PHONY: static-analysis-psalm +static-analysis-psalm: + $(PHP) ./vendor/bin/psalm + +.PHONY: unit-tests +unit-tests: + $(PHP) ./vendor/bin/phpunit diff --git a/admin/vendor/mjaschen/phpgeo/README.md b/admin/vendor/mjaschen/phpgeo/README.md new file mode 100644 index 000000000..09627b4ab --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/README.md @@ -0,0 +1,273 @@ +# phpgeo - A Simple Geo Library for PHP + +phpgeo provides abstractions to geographical coordinates (including support for different ellipsoids) and allows you to calculate geographical distances between coordinates with high precision. + +[![Latest Stable Version](https://poser.pugx.org/mjaschen/phpgeo/v)](//packagist.org/packages/mjaschen/phpgeo) +[![Total Downloads](https://poser.pugx.org/mjaschen/phpgeo/downloads)](//packagist.org/packages/mjaschen/phpgeo) +[![phpgeo Tests](https://github.com/mjaschen/phpgeo/actions/workflows/php.yml/badge.svg)](https://github.com/mjaschen/phpgeo/actions/workflows/php.yml) +[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/mjaschen/phpgeo/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/mjaschen/phpgeo/?branch=master) +[![License](https://poser.pugx.org/mjaschen/phpgeo/license)](//packagist.org/packages/mjaschen/phpgeo) + +## Table of Contents + + + +- [phpgeo - A Simple Geo Library for PHP](#phpgeo---a-simple-geo-library-for-php) + - [Table of Contents](#table-of-contents) + - [Requirements](#requirements) + - [Documentation](#documentation) + - [Installation](#installation) + - [License](#license) + - [Features](#features) + - [Examples/Usage](#examplesusage) + - [Distance between two coordinates (Vincenty's Formula)](#distance-between-two-coordinates-vincentys-formula) + - [Simplifying a polyline](#simplifying-a-polyline) + - [Polygon contains a point (e.g. "GPS geofence")](#polygon-contains-a-point-eg-gps-geofence) + - [Formatted output of coordinates](#formatted-output-of-coordinates) + - [Decimal Degrees](#decimal-degrees) + - [Degrees/Minutes/Seconds (DMS)](#degreesminutesseconds-dms) + - [GeoJSON](#geojson) + - [Development](#development) + - [Run Tests](#run-tests) + - [Miscellaneous](#miscellaneous) + - [Credits](#credits) + + + +## Requirements + +Minimum required PHP version is 7.3. *phpgeo* fully supports PHP 8. + +The 3.x releases require PHP >= 7.2 but don't get feature updates any longer. Bugfixes will be backported. + +The 2.x releases require PHP >= 7.0 but don't get feature updates any longer. Bugfixes won't be backported. + +The 1.x release line has support for PHP >= 5.4. Bugfixes won't be backported. + +## Documentation + +The documentation is available at https://phpgeo.marcusjaschen.de/ + +## Installation + +Using [Composer](https://getcomposer.org), just add it to your `composer.json` by running: + +``` +composer require mjaschen/phpgeo +``` + +## Upgrading + +Update the version constraint in the project's `composer.json` and +run `composer update` or require the new version by running: + +```shell +composer require mjaschen/phpgeo:^4.0 +``` + +## License + +Starting with version 2.0.0 phpgeo is licensed under the MIT license. Older versions were GPL-licensed. + +## Features + +**Info:** Please visit the **[documentation site](https://phpgeo.marcusjaschen.de/)** for complete and up-to-date documentation with many examples! + +phpgeo provides the following features (follow the links for examples): + +- abstractions of several geometry objects ([coordinate/point](https://phpgeo.marcusjaschen.de/Geometries/Coordinate.html), + [line](https://phpgeo.marcusjaschen.de/Geometries/Line.html), + [polyline/GPS track](https://phpgeo.marcusjaschen.de/Geometries/Polyline.html), + [polygon](https://phpgeo.marcusjaschen.de/Geometries/Polygon.html) +- support for different [ellipsoids](https://phpgeo.marcusjaschen.de/Geometries/Ellipsoid.html), e.g. WGS-84 +- [length/distance/perimeter calculations](https://phpgeo.marcusjaschen.de/Calculations/Distance_and_Length.html) + with different implementations (Haversine, Vincenty) +- [Geofence](https://phpgeo.marcusjaschen.de/Calculations/Geofence.html) calculation, + i.e. answering the question "Is this point contained in that area/polygon?" and other [intersection](https://phpgeo.marcusjaschen.de/Comparisons/Intersections.html) checks between different geometries +- [formatting and output](https://phpgeo.marcusjaschen.de/Formatting_and_Output/index.html) of geometry objects + (GeoJSON, nice strings, e. g. `18° 54′ 41″ -155° 40′ 42″`) +- calculation of [bearing angle between two points](https://phpgeo.marcusjaschen.de/Calculations/Bearing_and_Destination.html#page_Bearing-between-two-points) + (spherical or with Vincenty's formula) +- calculation of a [destination point for a given starting point](https://phpgeo.marcusjaschen.de/Calculations/Bearing_and_Destination.html#page_Destination-point-for-given-bearing-and-distance), + bearing angle, and distance (spherical or with Vincenty's formula) +- calculation of the [perpendicular distance between a point and a line](https://phpgeo.marcusjaschen.de/Calculations/Perpendicular_Distance.html) +- calculation of the [Cardinal Distances between two points](https://phpgeo.marcusjaschen.de/Calculations/Cardinal_Distance.html) +- getting segments of a [polyline](https://phpgeo.marcusjaschen.de/Geometries/Polyline.html#page_Segments) + /[polygon](https://phpgeo.marcusjaschen.de/Geometries/Polygon.html#page_Segments), +- [reversing direction](https://phpgeo.marcusjaschen.de/Geometries/Polygon.html#page_Reverse-Direction) + of polyline/polygon + +## Examples/Usage + +This list is incomplete, please visit the [documentation site](https://phpgeo.marcusjaschen.de/) +for the full monty of documentation and examples! + +### Distance between two coordinates (Vincenty's Formula) + +Use the calculator object directly: + +```php +getDistance($coordinate1, $coordinate2); // returns 128130.850 (meters; ≈128 kilometers) +``` + +or call the `getDistance()` method of a Coordinate object by injecting a calculator object: + +```php +getDistance($coordinate2, new Vincenty()); // returns 128130.850 (meters; ≈128 kilometers) +``` + +### Simplifying a polyline + +Polylines can be simplified to save storage space or bandwidth. Simplification is done with the [Ramer–Douglas–Peucker algorithm](https://en.wikipedia.org/wiki/Ramer–Douglas–Peucker_algorithm) (AKA Douglas-Peucker algorithm). + +```php +addPoint(new Coordinate(10.0, 10.0)); +$polyline->addPoint(new Coordinate(20.0, 20.0)); +$polyline->addPoint(new Coordinate(30.0, 10.0)); + +$processor = new Simplify($polyline); + +// remove all points which perpendicular distance is less +// than 1500 km from the surrounding points. +$simplified = $processor->simplify(1500000); + +// simplified is the polyline without the second point (which +// perpendicular distance is ~1046 km and therefore below +// the simplification threshold) +``` + +### Polygon contains a point (e.g. "GPS geofence") + +phpgeo has a polygon implementation which can be used to determinate if a point is contained in it or not. +A polygon consists of at least three points. Points are instances of the `Coordinate` class. + +**Warning:** The calculation gives wrong results if the polygons has points on both sides of the 180/-180 degrees meridian. + +```php +addPoint(new Coordinate(-12.085870,-77.016261)); +$geofence->addPoint(new Coordinate(-12.086373,-77.033813)); +$geofence->addPoint(new Coordinate(-12.102823,-77.030938)); +$geofence->addPoint(new Coordinate(-12.098669,-77.006476)); + +$outsidePoint = new Coordinate(-12.075452, -76.985079); +$insidePoint = new Coordinate(-12.092542, -77.021540); + +var_dump($geofence->contains($outsidePoint)); // returns bool(false) the point is outside the polygon +var_dump($geofence->contains($insidePoint)); // returns bool(true) the point is inside the polygon +``` + +### Formatted output of coordinates + +You can format a coordinate in different styles. + +#### Decimal Degrees + +```php +format(new DecimalDegrees()); +``` + +#### Degrees/Minutes/Seconds (DMS) + +```php +format($formatter); // 18° 54′ 41″ -155° 40′ 42″ + +$formatter->setSeparator(", ") + ->useCardinalLetters(true) + ->setUnits(DMS::UNITS_ASCII); + +echo $coordinate->format($formatter); // 18° 54' 41" N, 155° 40' 42" W +``` + +#### GeoJSON + +```php +format(new GeoJSON()); // { "type" : "point" , "coordinates" : [ -155.678268, 18.911306 ] } +``` + +## Development + +### Run Tests + +Before submitting a pull request, please be sure to run all checks and tests and ensure everything is green. + +- lint PHP files for syntax errors: `composer ci:lint` +- run static analysis with [Psalm][] and report errors: `composer ci:psalm` +- run unit tests with PHPUnit: `composer ci:tests` + +To run all checks and tests at once, just use `composer ci`. + +Of course, it's possible to use the test runners directly, e.g. for PHPUnit: + +```shell +./vendor/bin/phpunit +``` + +Psalm: + +```shell +./vendor/bin/psalm +``` + +## Credits + +* Marcus Jaschen and [all contributors](https://github.com/mjaschen/phpgeo/graphs/contributors) +* [Chris Veness](http://www.movable-type.co.uk/scripts/latlong-vincenty.html) - JavaScript implementation of the [Vincenty formula](http://en.wikipedia.org/wiki/Vincenty%27s_formulae) for distance calculation +* Ersts,P.J., Horning, N., and M. Polin[Internet] Perpendicular Distance Calculator(version 1.2.2) [Documentation](http://biodiversityinformatics.amnh.org/open_source/pdc/documentation.php). American Museum of Natural History, Center for Biodiversity and Conservation. Available from http://biodiversityinformatics.amnh.org/open_source/pdc. Accessed on 2013-07-07. +* W. Randolph Franklin, PNPOLY - Point Inclusion in Polygon Test [Documentation](http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html) + +[Psalm]: https://github.com/vimeo/psalm diff --git a/admin/vendor/mjaschen/phpgeo/composer.json b/admin/vendor/mjaschen/phpgeo/composer.json new file mode 100644 index 000000000..d4145f8c7 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/composer.json @@ -0,0 +1,77 @@ +{ + "name": "mjaschen/phpgeo", + "description": "Simple Yet Powerful Geo Library", + "keywords": [ + "distance", + "area", + "coordinate", + "geo", + "gis", + "bounds", + "ellipsoid", + "calculation", + "polyline", + "polygon", + "geofence", + "simplify", + "length", + "vincenty", + "haversine", + "bearing", + "projection", + "gps", + "earth", + "track", + "point", + "perpendicular" + ], + "homepage": "https://phpgeo.marcusjaschen.de/", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Marcus Jaschen", + "email": "mjaschen@gmail.com", + "homepage": "https://www.marcusjaschen.de/" + } + ], + "readme": "README.md", + "support" : { + "issues" : "https://github.com/mjaschen/phpgeo/issues", + "docs": "https://phpgeo.marcusjaschen.de/Installation.html", + "email" : "mjaschen@gmail.com" + }, + "require": { + "php": "^7.3 || ^8.0" + }, + "autoload": { + "psr-4": { + "Location\\": "src/" + } + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.13", + "squizlabs/php_codesniffer": "^3.6" + }, + "scripts": { + "ci:composer-validate": "composer validate --no-check-all --no-check-lock --strict", + "ci:lint": "find src tests -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l", + "ci:psalm": "./vendor/bin/psalm", + "ci:sniff": "./vendor/bin/phpcs src tests", + "ci:tests": "./vendor/bin/phpunit tests/", + "ci:static": [ + "@ci:composer-validate", + "@ci:lint", + "@ci:psalm", + "@ci:sniff" + ], + "ci:dynamic": [ + "@ci:tests" + ], + "ci": [ + "@ci:static", + "@ci:dynamic" + ] + } +} diff --git a/admin/vendor/mjaschen/phpgeo/docs/#intersection-polyline-simple.dxf b/admin/vendor/mjaschen/phpgeo/docs/#intersection-polyline-simple.dxf new file mode 100644 index 000000000..b8939b47e --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/#intersection-polyline-simple.dxf @@ -0,0 +1,3408 @@ +999 +dxfrw 0.6.3 + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1021 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$INSBASE + 10 +0 + 20 +0 + 30 +0 + 9 +$EXTMIN + 10 +-8 + 20 +-5 + 30 +0 + 9 +$EXTMAX + 10 +5 + 20 +10 + 30 +0 + 9 +$LIMMIN + 10 +0 + 20 +0 + 9 +$LIMMAX + 10 +420 + 20 +297 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1 + 9 +$ATTMODE + 70 + 0 + 9 +$TEXTSIZE + 40 +2.5 + 9 +$TRACEWID + 40 +15.68 + 9 +$TEXTSTYLE + 7 +STANDARD + 9 +$CLAYER + 8 +Bounds 5 + 9 +$CELTYPE + 6 +BYLAYER + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +2.5 + 9 +$DIMASZ + 40 +2.5 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMDLI + 40 +3.75 + 9 +$DIMRND + 40 +0 + 9 +$DIMDLE + 40 +0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMTP + 40 +0 + 9 +$DIMTM + 40 +0 + 9 +$DIMTXT + 40 +2.5 + 9 +$DIMCEN + 40 +2.5 + 9 +$DIMTSZ + 40 +0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 0 + 9 +$DIMTOH + 70 + 0 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 1 + 9 +$DIMZIN + 70 + 8 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 3 + 9 +$DIMALTF + 40 +0.03937 + 9 +$DIMLFAC + 40 +1 + 9 +$DIMTOFL + 70 + 1 + 9 +$DIMTVP + 40 +0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +STANDARD + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1 + 9 +$DIMGAP + 40 +0.625 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 0 + 9 +$DIMTZIN + 70 + 8 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 4 + 9 +$DIMTDEC + 70 + 2 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 3 + 9 +$DIMTXSTY + 7 +STANDARD + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 2 + 9 +$DIMALTRND + 40 +0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 44 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 +STANDARD + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$DIMFXL + 40 +1 + 9 +$DIMFXLON + 70 + 0 + 9 +$DIMJOGANG + 40 +0.7854 + 9 +$DIMTFILL + 70 + 0 + 9 +$DIMTFILLCLR + 70 + 0 + 9 +$DIMARCSYM + 70 + 0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +1 + 9 +$FILLETRAD + 40 +0 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 2 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0 + 9 +$PELEVATION + 40 +0 + 9 +$THICKNESS + 40 +0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0 + 9 +$CHAMFERB + 40 +0 + 9 +$CHAMFERC + 40 +0 + 9 +$CHAMFERD + 40 +0 + 9 +$SKPOLY + 70 + 0 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 34 + 9 +$PDSIZE + 40 +0 + 9 +$PLINEWID + 40 +0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 2 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +20000 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSXDIR + 10 +1 + 20 +0 + 30 +0 + 9 +$UCSYDIR + 10 +0 + 20 +1 + 30 +0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGBOTTOM + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGLEFT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGRIGHT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGFRONT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGBACK + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSXDIR + 10 +1 + 20 +0 + 30 +0 + 9 +$PUCSYDIR + 10 +0 + 20 +1 + 30 +0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGBOTTOM + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGLEFT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGRIGHT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGFRONT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGBACK + 10 +0 + 20 +0 + 30 +0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0 + 9 +$USERR2 + 40 +0 + 9 +$USERR3 + 40 +0 + 9 +$USERR4 + 40 +0 + 9 +$USERR5 + 40 +0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0 + 20 +0 + 30 +0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +0 + 20 +0 + 30 +0 + 9 +$PEXTMAX + 10 +0 + 20 +0 + 30 +0 + 9 +$GRIDMODE + 70 + 1 + 9 +$SNAPSTYLE + 70 + 0 + 9 +$PLIMMIN + 10 +0 + 20 +0 + 9 +$PLIMMAX + 10 +297 + 20 +210 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +20 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 1 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 0 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0 + 9 +$OLESTARTUP +290 + 0 + 9 +$SORTENTS +280 + 127 + 9 +$INDEXCTL +280 + 0 + 9 +$HIDETEXT +280 + 1 + 9 +$XCLIPFRAME +290 + 0 + 9 +$HALOGAP +280 + 0 + 9 +$OBSCOLOR + 70 + 257 + 9 +$OBSLTYPE +280 + 0 + 9 +$INTERSECTIONDISPLAY +280 + 0 + 9 +$INTERSECTIONCOLOR + 70 + 257 + 9 +$DIMASSOC +280 + 1 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 + 0 + 9 +$LENSLENGTH + 40 +50 + 9 +$CAMERAHEIGHT + 40 +0 + 9 +$STEPSPERSEC + 40 +2 + 9 +$STEPSIZE + 40 +50 + 9 +$3DDWFPREC + 40 +2 + 9 +$PSOLWIDTH + 40 +5 + 9 +$PSOLHEIGHT + 40 +80 + 9 +$LOFTANG1 + 40 +1.570796326794897 + 9 +$LOFTANG2 + 40 +1.570796326794897 + 9 +$LOFTMAG1 + 40 +0 + 9 +$LOFTMAG2 + 40 +0 + 9 +$LOFTPARAM + 70 + 7 + 9 +$LOFTNORMALS +280 + 1 + 9 +$LATITUDE + 40 +1 + 9 +$LONGITUDE + 40 +1 + 9 +$NORTHDIRECTION + 40 +0 + 9 +$TIMEZONE + 70 +-8000 + 9 +$LIGHTGLYPHDISPLAY +280 + 1 + 9 +$TILEMODELIGHTSYNCH +280 + 1 + 9 +$SOLIDHIST +280 + 1 + 9 +$SHOWHIST +280 + 1 + 9 +$DWFFRAME +280 + 2 + 9 +$DGNFRAME +280 + 0 + 9 +$REALWORLDSCALE +290 + 1 + 9 +$INTERFERECOLOR + 62 + 1 + 9 +$CSHADOW +280 + 0 + 9 +$SHADOWPLANELOCATION + 40 +0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +31 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*ACTIVE + 70 + 0 + 10 +0 + 20 +0 + 11 +1 + 21 +1 + 12 +10.80843339947816 + 22 +7.089026436766691 + 13 +0 + 23 +0 + 14 +10 + 24 +10 + 15 +10 + 25 +10 + 16 +0 + 26 +0 + 36 +1 + 17 +0 + 27 +0 + 37 +0 + 40 +26.91031746062092 + 41 +1.720970537261698 + 42 +50 + 43 +0 + 44 +0 + 50 +0 + 51 +0 + 71 + 0 + 72 + 100 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 1 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 1 +110 +0 +120 +0 +130 +0 +111 +1 +121 +0 +131 +0 +112 +0 +122 +1 +132 +0 + 79 + 0 +146 +0 +348 +10020 + 60 + 7 + 61 + 5 +292 +1 +282 + 1 +141 +0 +142 +0 + 63 + 250 +421 +3358443 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 4 + 0 +LTYPE + 5 +14 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +15 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +16 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +32 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT + 70 + 0 + 3 +Dot . . . . . . . . . . . . . . . . . . . . . . + 72 + 65 + 73 + 2 + 40 +6.35 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +33 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOTTINY + 70 + 0 + 3 +Dot (.15x) ..................................... + 72 + 65 + 73 + 2 + 40 +0.9525 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +34 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT2 + 70 + 0 + 3 +Dot (.5x) ..................................... + 72 + 65 + 73 + 2 + 40 +3.175 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +35 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOTX2 + 70 + 0 + 3 +Dot (2x) . . . . . . . . . . . . . + 72 + 65 + 73 + 2 + 40 +12.7 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +36 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED + 70 + 0 + 3 +Dashed _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +19.05 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +37 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHEDTINY + 70 + 0 + 3 +Dashed (.15x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +2.8575 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +38 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED2 + 70 + 0 + 3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +9.524999999999999 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +39 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHEDX2 + 70 + 0 + 3 +Dashed (2x) ____ ____ ____ ____ ____ ___ + 72 + 65 + 73 + 2 + 40 +38.09999999999999 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +3A +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT + 70 + 0 + 3 +Dash dot __ . __ . __ . __ . __ . __ . __ . __ + 72 + 65 + 73 + 4 + 40 +25.4 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +3B +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOTTINY + 70 + 0 + 3 +Dash dot (.15x) _._._._._._._._._._._._._._._. + 72 + 65 + 73 + 4 + 40 +3.81 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +3C +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT2 + 70 + 0 + 3 +Dash dot (.5x) _._._._._._._._._._._._._._._. + 72 + 65 + 73 + 4 + 40 +12.7 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +3D +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOTX2 + 70 + 0 + 3 +Dash dot (2x) ____ . ____ . ____ . ___ + 72 + 65 + 73 + 4 + 40 +50.8 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +3E +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE + 70 + 0 + 3 +Divide ____ . . ____ . . ____ . . ____ . . ____ + 72 + 65 + 73 + 6 + 40 +31.75 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +3F +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDETINY + 70 + 0 + 3 +Divide (.15x) __..__..__..__..__..__..__..__.._ + 72 + 65 + 73 + 6 + 40 +4.7625 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +40 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE2 + 70 + 0 + 3 +Divide (.5x) __..__..__..__..__..__..__..__.._ + 72 + 65 + 73 + 6 + 40 +15.875 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +41 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDEX2 + 70 + 0 + 3 +Divide (2x) ________ . . ________ . . _ + 72 + 65 + 73 + 6 + 40 +63.5 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +42 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER + 70 + 0 + 3 +Border __ __ . __ __ . __ __ . __ __ . __ __ . + 72 + 65 + 73 + 6 + 40 +44.45 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +43 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDERTINY + 70 + 0 + 3 +Border (.15x) __.__.__.__.__.__.__.__.__.__.__. + 72 + 65 + 73 + 6 + 40 +6.6675 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +44 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER2 + 70 + 0 + 3 +Border (.5x) __.__.__.__.__.__.__.__.__.__.__. + 72 + 65 + 73 + 6 + 40 +22.225 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +45 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDERX2 + 70 + 0 + 3 +Border (2x) ____ ____ . ____ ____ . ___ + 72 + 65 + 73 + 6 + 40 +88.89999999999999 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +46 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER + 70 + 0 + 3 +Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ + 72 + 65 + 73 + 4 + 40 +50.8 + 49 +31.75 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +6.35 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +47 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTERTINY + 70 + 0 + 3 +Center (.15x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 + 65 + 73 + 4 + 40 +7.619999999999999 + 49 +4.7625 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0.9525 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +48 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER2 + 70 + 0 + 3 +Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 + 65 + 73 + 4 + 40 +28.575 + 49 +19.05 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +3.175 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +49 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTERX2 + 70 + 0 + 3 +Center (2x) ________ __ ________ __ _____ + 72 + 65 + 73 + 4 + 40 +101.6 + 49 +63.5 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +12.7 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LAYER + 5 +10 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4A +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 1 + 70 + 0 + 62 + 16 +420 +8388608 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4B +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 2 + 70 + 0 + 62 + 56 +420 +8421376 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4C +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 3 + 70 + 1 + 62 + 96 +420 +32768 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4D +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 4 + 70 + 0 + 62 + 136 +420 +32896 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4E +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 5 + 70 + 1 + 62 + 176 +420 + 128 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4F +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 1 + 70 + 0 + 62 + 1 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +50 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 2 + 70 + 0 + 62 + 2 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +51 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 3 + 70 + 1 + 62 + 3 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +52 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 4 + 70 + 0 + 62 + 4 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +53 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 5 + 70 + 1 + 62 + 5 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 3 + 0 +STYLE + 5 +54 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0 + 41 +1 + 50 +0 + 71 + 0 + 42 +1 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +APPID + 5 +12 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +55 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +LibreCad + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 1 +100 +AcDbDimStyleTable + 71 + 1 + 0 +DIMSTYLE +105 +56 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 + 40 +2.5 + 41 +2.5 + 42 +0.625 + 43 +0.38 + 44 +1.25 + 45 +0 + 46 +0 + 47 +0 + 48 +0 + 49 +1 +140 +2.5 +141 +0.09 +142 +0 +143 +25.4 +144 +1 +145 +0 +146 +1 +147 +0.625 +148 +0 + 71 + 0 + 72 + 0 + 73 + 0 + 74 + 1 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 8 + 79 + 0 +170 + 0 +171 + 2 +172 + 0 +173 + 0 +174 + 0 +175 + 0 +176 + 0 +177 + 0 +178 + 0 +179 + 2 +271 + 4 +272 + 4 +273 + 2 +274 + 2 +275 + 0 +276 + 0 +277 + 2 +278 + 44 +279 + 0 +280 + 0 +281 + 0 +282 + 0 +283 + 1 +284 + 0 +285 + 0 +286 + 0 +288 + 0 +289 + 3 +340 +STANDARD +341 + +371 + -2 +372 + -2 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +BLOCK_RECORD + 5 +1F +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +1E +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space + 70 + 0 +280 + 1 +281 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +20 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0 + 20 +0 + 30 +0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +21 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +1C +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0 + 20 +0 + 30 +0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +1D +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LINE + 5 +57 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-4 + 20 +-2 + 11 +5 + 21 +2 + 0 +LINE + 5 +58 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +5 + 20 +2 + 11 +-1 + 21 +7 + 0 +LINE + 5 +59 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-1 + 20 +7 + 11 +-3 + 21 +4 + 0 +LINE + 5 +5A +100 +AcDbEntity + 8 +Line 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-8 + 20 +3 + 11 +-5 + 21 +-5 + 0 +LINE + 5 +5B +100 +AcDbEntity + 8 +Line 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-5 + 20 +-5 + 11 +4 + 21 +-3 + 0 +LINE + 5 +5C +100 +AcDbEntity + 8 +Line 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +15 + 20 +18 + 11 +21 + 21 +14 + 0 +LINE + 5 +5D +100 +AcDbEntity + 8 +Line 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +21 + 20 +14 + 11 +11 + 21 +13 + 0 +LWPOLYLINE + 5 +5E +100 +AcDbEntity + 8 +Bounds 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +-4 + 20 +-2 + 10 +5 + 20 +-2 + 10 +5 + 20 +7 + 10 +-4 + 20 +7 + 0 +LWPOLYLINE + 5 +5F +100 +AcDbEntity + 8 +Bounds 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +4 + 20 +-5 + 10 +-8 + 20 +-5 + 10 +-8 + 20 +3 + 10 +4 + 20 +3 + 0 +LWPOLYLINE + 5 +60 +100 +AcDbEntity + 8 +Bounds 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +11 + 20 +13 + 10 +21 + 20 +13 + 10 +21 + 20 +18 + 10 +11 + 20 +18 + 0 +LINE + 5 +61 +100 +AcDbEntity + 8 +Line 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-6 + 20 +9 + 11 +-1 + 21 +5 + 0 +LINE + 5 +62 +100 +AcDbEntity + 8 +Line 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-1 + 20 +5 + 11 +1 + 21 +10 + 0 +LWPOLYLINE + 5 +63 +100 +AcDbEntity + 8 +Bounds 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +1 + 20 +10 + 10 +-6 + 20 +10 + 10 +-6 + 20 +5 + 10 +1 + 20 +5 + 0 +LINE + 5 +64 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +13 + 20 +24 + 11 +9 + 21 +22 + 0 +LINE + 5 +65 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +8 + 20 +15 + 11 +14 + 21 +20 + 0 +LINE + 5 +66 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +14 + 20 +20 + 11 +13 + 21 +24 + 0 +LWPOLYLINE + 5 +67 +100 +AcDbEntity + 8 +Bounds 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +8 + 20 +15 + 10 +14 + 20 +15 + 10 +14 + 20 +24 + 10 +8 + 20 +24 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_GROUP +350 +D + 0 +DICTIONARY + 5 +D +330 +C +100 +AcDbDictionary +281 + 1 + 0 +PLOTSETTINGS + 5 +68 +100 +AcDbPlotSettings + 6 +1x1 + 40 +0 + 41 +0 + 42 +0 + 43 +0 + 0 +ENDSEC + 0 +EOF diff --git a/admin/vendor/mjaschen/phpgeo/docs/000_Introduction.md b/admin/vendor/mjaschen/phpgeo/docs/000_Introduction.md new file mode 100644 index 000000000..dff0156ac --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/000_Introduction.md @@ -0,0 +1,22 @@ +# What is *phpgeo?* + +_phpgeo_ is a small PHP library which provides abstractions to geographical +coordinates (including support for different ellipsoids), polylines +("GPS Tracks"), polygons, bounds, and more. _phpgeo_ allows you to perform +different calculations with these abstractions, as distances, track +lengths, etc. + +_phpgeo_ is developed by [Marcus Jaschen](https://www.marcusjaschen.de/) and all +[contributors](https://github.com/mjaschen/phpgeo/graphs/contributors). + +_phpgeo_ is licensed under the [MIT License](https://opensource.org/licenses/MIT). + +The project is hosted on Github: + +- [Github Project Site](https://github.com/mjaschen/phpgeo) +- [Issue Tracker](https://github.com/mjaschen/phpgeo/issues) + +## Privacy + +The privacy statement for this documentation site can be found here: +[Datenschutzerklärung](https://www.marcusjaschen.de/datenschutzerklaerung/) diff --git a/admin/vendor/mjaschen/phpgeo/docs/010_Installation.md b/admin/vendor/mjaschen/phpgeo/docs/010_Installation.md new file mode 100644 index 000000000..a67123376 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/010_Installation.md @@ -0,0 +1,24 @@ +# Getting phpgeo + +## Requirements + +_phpgeo_ requires at least PHP 7.3. _phpgeo_ fully supports PHP 8. + +The 3.x releases require PHP >= 7.2 but don't get feature updates any longer. Bugfixes will be backported. + +The 2.x releases require PHP >= 7.0 but don't get feature updates any longer. Bugfixes won't be backported. + +The 1.x release line has support for PHP >= 5.4. Bugfixes won't be backported. + +## Installation + +_phpgeo_ is best be installed using Composer. Please visit the +[Composer website](https://getcomposer.org/) website for more information. + +To install _phpgeo,_ simply “require” it using Composer: + +``` shell +composer require mjaschen/phpgeo +``` + +_phpgeo_ is now ready to be used in your project! diff --git a/admin/vendor/mjaschen/phpgeo/docs/015_Upgrading.md b/admin/vendor/mjaschen/phpgeo/docs/015_Upgrading.md new file mode 100644 index 000000000..454fe7336 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/015_Upgrading.md @@ -0,0 +1,38 @@ +# Upgrading phpgeo + +## Update from phpgeo 3.x to phpgeo 4.x + +### Requirements + +- _phpgeo_ 4.x requires at least PHP 7.3 and fully supports PHP 8 + +### Update phpgeo + +- run `composer require mjaschen/phpgeo:^4.0` or +- update the version constraint in your `composer.json` to `^4.0` and run `composer update` + +### Update Your Code + +- Setters in `DMS` and `Line` classes are deprecated and will be removed + with the next release. Use constructor arguments instead. + +No breaking changes were introduced with *phpgeo* 3.0. + +## Update from phpgeo 2.x to phpgeo 3.x + +### Requirements + +- _phpgeo_ 3.x requires at least PHP 7.2 + +### Update phpgeo + +- run `composer require mjaschen/phpgeo:^3.0` or +- update the version constraint in your `composer.json` to `^3.0` and run `composer update` + +### Update Your Code + +The result of `Ellipsoid::getName()` for the built-in *WGS-84* ellipsoid returned `World␣Geodetic␣System␣␣1984` in *phpgeo* 2.x (two space characters before `1984`). Starting with *phpgeo* 3.0, the result is `World␣Geodetic␣System␣1984` (single space character before `1984`). Please verify that your code is still working if you're using that result. + +Starting with *phpgeo* 3.0 class constant visiblity modifiers are used. One class constant was changed to *private* visibility: `BearingSpherical::EARTH_RADIUS`. Please verify that your code isn't using that class constant. + +No further breaking changes were introduced with *phpgeo* 3.0. diff --git a/admin/vendor/mjaschen/phpgeo/docs/020_Development.md b/admin/vendor/mjaschen/phpgeo/docs/020_Development.md new file mode 100644 index 000000000..7a8bead75 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/020_Development.md @@ -0,0 +1,96 @@ +# Development + +## Run Tests + +_phpgeo_ provides unit tests with a quite good coverage. For an easy usage, +the test command is wrapped as a Composer script: + +``` shell +composer ci:tests +``` + +Of course it's possible to run PHPUnit directly: + +``` shell +./vendor/bin/phpunit +``` + +To test against another PHP version you can use Docker. The following command runs +the tests using PHP 7.3: + +``` shell +docker run -it --rm --name phpgeo-phpunit \ + -v "$PWD":/usr/src/phpgeo \ + -w /usr/src/phpgeo php:7.3-cli \ + php vendor/bin/phpunit +``` + +Or PHP 7.4: + +``` shell +docker run -it --rm --name phpgeo-phpunit \ + -v "$PWD":/usr/src/phpgeo \ + -w /usr/src/phpgeo php:7.4-cli \ + php vendor/bin/phpunit +``` + +PHP 8.0: + +``` shell +docker run -it --rm --name phpgeo-phpunit \ + -v "$PWD":/usr/src/phpgeo \ + -w /usr/src/phpgeo php:8.0-cli \ + php vendor/bin/phpunit +``` + +PHP 8.1: + +``` shell +docker run -it --rm --name phpgeo-phpunit \ + -v "$PWD":/usr/src/phpgeo \ + -w /usr/src/phpgeo php:8.1-cli \ + php vendor/bin/phpunit +``` + +Alongside with the unit tests, static test runners are also provided. Run the lint +command to ensure the sources don't contain any syntax error: + +``` shell +composer ci:lint +``` + +A static code analysis with [Psalm](https://psalm.dev/) is configured as well: + +``` shell +composer ci:psalm +``` + +It's possible to run all tests at once: + +``` shell +composer ci +``` + +… or run all CI tasks with different PHP versions one after another: + +```shell +for PHP_VERSION in 7.3 7.4 8.0 8.1 ; do \ + docker run -it --rm -v "$PWD":/phpgeo -w /phpgeo \ + ghcr.io/mjaschen/php:${PHP_VERSION}-cli-mj composer ci || break ; \ +done +``` + +## Creating the documentation + +*phpgeo's* documentation is generated with [Daux](https://daux.io/) from Markdown files. +The `Makefile` provides a helper target for generating the complete documentation: + +``` shell +make docs +``` + +*Daux* can also be run from its official Docker image: + +``` shell +docker run --rm -it -v "$(pwd)":/phpgeo -w /phpgeo daux/daux.io daux generate -d build/daux +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/110_Coordinate.md b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/110_Coordinate.md new file mode 100644 index 000000000..3692808de --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/110_Coordinate.md @@ -0,0 +1,15 @@ +# Coordinate + +The `Coordinate` class is the most important class of phpgeo and provides the +base for all features. It's a representation of a geographic location and +consists of three parts: + +- Geographic Latitude +- Geographic Longitude +- Ellipsoid + +Geographic latitude and longitude values are float numbers between +-90.0 and 90.0 (degrees latitude) and -180.0 and 180.0 (degrees longitude). + +The Ellipsoid is a representation of an approximated shape of the earth and +is abstracted in its own [`Ellipsoid`](Ellipsoid) Link class. diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/120_Line.md b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/120_Line.md new file mode 100644 index 000000000..36b596f82 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/120_Line.md @@ -0,0 +1,170 @@ +# Line + +[TOC] + +A line consists of two points, i. e. instances of the `Coordinate` class. + +## Length + +The `Line` class provides a method to calculate its own length. The method +expects an instance of a class which implements the `DistanceInterface`. + +``` php +getLength(new Haversine()); + +printf("The line has a length of %.3f meters\n", $length); +``` + +`Haversine` is one of the currently two available classes for +distance calculation. The other one is named `Vincenty`. + +The code above will produce the output below: + +``` plaintext +The line has a length of 13013.849 meters +``` + +## Midpoint + +The midpoint of a line is calculated by following the Great Circle (defined by the two endpoints) and dividing the line into two halves. + +``` php +getMidpoint(); + +printf( + 'The midpoint of the line is located at %.3f degrees latitude and %.3f degrees longitude.%s', + $midpoint->getLat(), + $midpoint->getLng(), + PHP_EOL +); + +printf( + 'Its distance from the first point is %.1f meters, its distance from the second point is %.1f meters.%s', + $line->getPoint1()->getDistance($midpoint, new Haversine()), + $line->getPoint2()->getDistance($midpoint, new Haversine()), + PHP_EOL +); +``` + +The code above produces the output below: + +``` plaintext +The midpoint of the line is located at 44.719 degrees latitude and 90.000 degrees longitude. +Its distance from the first point is 3935890.0 meters, its distance from the second point is 3935890.0 meters. +``` + +## Intermediate Point + +Similar to the midpoint calculation but divides the line at the given fraction (between 0.0 … 1.0; but values outside that range work as well). + +``` php +getIntermediatePoint(0.25); + +printf( + 'The first quarter of the line ends at %s%s', + $result->format(new DecimalMinutes(' ')), + PHP_EOL +); +``` + +The code above produces the output below: + +``` plaintext +The first quarter of the line ends at 00° 15.001′ 000° 14.999′ +``` + +## Bearing + +The bearing of an instance can be calculated using the `getBearing()` method. +An instance of `BearingInterface` must be provided as method argument. + +``` php +getBearing(new BearingEllipsoidal()); + +printf("The line has a bearing of %.2f degrees\n", $bearing); +``` + +`BearingEllipsoidal` is one of the currently two available classes for +bearing calculation. The other one is named `BearingSpherical`. + +The code above will produce the output below: + +``` plaintext +The line has a bearing of 328.67 degrees +``` + +This ist the so called _initial bearing._ There exist another bearing angle, +called the _final bearing._ It can be calculated as well: + +``` php +getFinalBearing(new BearingEllipsoidal()); + +printf("The line has a final bearing of %.2f degrees\n", $bearing); +``` + +The code above will produce the output below: + +``` plaintext +The line has a final bearing of 328.59 degrees +``` + +See Bearing between two points @TODO Link for more information about bearings. diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/130_Polyline.md b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/130_Polyline.md new file mode 100644 index 000000000..3ec8a0766 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/130_Polyline.md @@ -0,0 +1,126 @@ +# Polyline + +[TOC] + +A polyline consists of an ordered list of locations, i. e. instances of +the `Coordinate` class. + +## Create a polyline + +To create a polyline, just instantiate the class and add points: + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polyline->addPoint(new Coordinate(54.5, 12.5)); +$polyline->addPoint(new Coordinate(55.5, 14.5)); +?> +``` + +It's possible to add points to the end of the polyline at every time with the `addPoint()` method. + +Use `addUniquePoint()` to add unique points, i.e. points which doesn't exist already in the polyline. + +## Segments + +It's possible to get a list of polyline segments. Segments are returned as an +array of `Line` instances. + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$track->addPoint(new Coordinate(54.5, 12.5)); +$track->addPoint(new Coordinate(55.5, 14.5)); + +foreach ($track->getSegments() as $segment) { + printf( + "Segment length: %0.2f kilometers\n", + ($segment->getLength(new Haversine()) / 1000) + ); +} +``` + +The code above will produce the output below: + +``` plaintext +Segment length: 232.01 kilometers +Segment length: 169.21 kilometers +``` + +## Length + +Length calculation is described in the [Distance and Length](../Calculations/Distance_and_Length) section. + +## Average Point + +The `getAveragePoint()` method returns a point which latitude and longitude is the average of latitude/longitude values from all polyline points. + +CAUTION: This method currently returns wrong values if the polyline crosses the date line at 180/-180 degrees longitude. + +## Reverse Direction + +It's possible to get a new instance with reversed direction while the +original polyline stays unchanged: + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$track->addPoint(new Coordinate(54.5, 12.5)); + +$reversed = $track->getReverse(); + +print_r($reversed); +``` + +The code above will produce the output below: + +``` plaintext +Location\Polyline Object +( + [points:protected] => Array + ( + [0] => Location\Coordinate Object + ( + [lat:protected] => 54.5 + [lng:protected] => 12.5 + [ellipsoid:protected] => Location\Ellipsoid Object + ( + [name:protected] => WGS-84 + [a:protected] => 6378137 + [f:protected] => 298.257223563 + ) + + ) + + [1] => Location\Coordinate Object + ( + [lat:protected] => 52.5 + [lng:protected] => 13.5 + [ellipsoid:protected] => Location\Ellipsoid Object + ( + [name:protected] => WGS-84 + [a:protected] => 6378137 + [f:protected] => 298.257223563 + ) + + ) + + ) + +) +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/140_Polygon.md b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/140_Polygon.md new file mode 100644 index 000000000..36e571a5d --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/140_Polygon.md @@ -0,0 +1,167 @@ +# Polygon + +[TOC] + +A polygon consists of an ordered list of locations, i. e. instances of +the `Coordinate` class. It's very similar to a polyline, but its start +and end points are connected. + +## Create a polygon + +To create a polygon, just instantiate the class and add points: + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polygon->addPoint(new Coordinate(54.5, 12.5)); +$polygon->addPoint(new Coordinate(55.5, 14.5)); +?> +``` + +It's possible to add points to the end at every time. + +## Get list of points + +`getPoints()` is used to get the list of points, the number of points can be +retrieved by calling `getNumberOfPoints()`: + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polygon->addPoint(new Coordinate(54.5, 12.5)); +$polygon->addPoint(new Coordinate(55.5, 14.5)); + +printf("The polygon consists of %d points:\n", $polygon->getNumberOfPoints()); + +foreach ($polygon->getPoints() as $point) { + echo $point->format(new DMS()) . PHP_EOL; +} +``` + +The code above will produce the output below: + +``` plaintext +The polygon consists of 3 points: +52° 30′ 00″ 013° 30′ 00″ +54° 30′ 00″ 012° 30′ 00″ +55° 30′ 00″ 014° 30′ 00″ +``` + +## Segments + +It's possible to get a list of polygon segments. Segments are +returned as an array of `Line` instances. + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polygon->addPoint(new Coordinate(54.5, 12.5)); +$polygon->addPoint(new Coordinate(55.5, 14.5)); + +foreach ($polygon->getSegments() as $line) { + printf("%0.3f m\n", $line->getLength(new Haversine())); +} +``` + +The code above will produce the output below: + +``` plaintext +232011.020 m +169207.795 m +339918.069 m +``` + +## Length/Perimeter + +Length calculation is described in the [Distance and Length](../Calculations/Distance_and_Length) section. + +## Area + +It's possible to calculate the area of an polygon. The result is given in square meters (m²). + +WARNING: The calculation gives inaccurate results. For relatively small polygons the error should be less than 1 %. + +``` php +addPoint(new Coordinate(0.0000000000, 0.0000000000)); +$polygon->addPoint(new Coordinate(0.0000000000, 0.0008983153)); +$polygon->addPoint(new Coordinate(0.0009043695, 0.0008983153)); +$polygon->addPoint(new Coordinate(0.0009043695, 0.0000000000)); + +printf( + 'Polygon Area = %f m², Perimeter = %f m%s', + $polygon->getArea(), + $polygon->getPerimeter(new \Location\Distance\Vincenty()), + PHP_EOL +); +``` + +The code above produces the output below: + +``` plaintext +Polygon Area = 10044.905261 m², Perimeter = 400.000000 m +``` + +## Geofence + +It's possible to check if a geometry object (point, line, polyline, +polygon) lies inside a polygon. The documentation can be found in +the <> @TODO section. + +## Reverse Direction + +It's possible to get a new instance with reversed direction while the +original polygon stays unchanged: + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polygon->addPoint(new Coordinate(64.1, - 21.9)); +$polygon->addPoint(new Coordinate(40.7, - 74.0)); +$polygon->addPoint(new Coordinate(33.9, - 118.4)); + +$reversed = $polygon->getReverse(); + +foreach ($reversed->getPoints() as $point) { + echo $point->format(new DecimalDegrees(', ')) . PHP_EOL; +} +``` + +The code above produces the output below: + +``` plaintext +33.90000, -118.40000 +40.70000, -74.00000 +64.10000, -21.90000 +52.50000, 13.50000 +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/200_Bounds.md b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/200_Bounds.md new file mode 100644 index 000000000..2f5b4f421 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/200_Bounds.md @@ -0,0 +1,26 @@ +# Bounds + +Bounds describe an area which is defined by its north-eastern and south-western points. + +All of *phpgeo's* geometries except for the `Coordindate` class provide a `getBounds()` method via the `GetBoundsTrait`. + +The `Bounds` class has a method to calculate the center point of the bounds object (works correctly for bounds that cross the dateline at 180/-180 degrees longitude too). + +## Create Bounds for a given center point and distance to the corners + +``` php +getName(), + $ellipsoid->getA(), + $ellipsoid->getB(), + $ellipsoid->getF() +); + +$ellipsoid = new Ellipsoid('GRS-80', 6378137, 298.257222); + +printf( + "%s: a=%f; b=%f; 1/f=%f\n", + $ellipsoid->getName(), + $ellipsoid->getA(), + $ellipsoid->getB(), + $ellipsoid->getF() +); +``` + +The first ellipsoid is created from one the the default configurations. The second one is created by providing a name and the values of *a* and *1/f.* + +The code above will produce the output below: + +``` plaintext +WGS-84: a=6378137.000000; b=6356752.314245; 1/f=298.257224 +GRS-80: a=6378137.000000; b=6356752.314133; 1/f=298.257222 +``` + +Please take a look into the [`Ellipsoid` source file](https://github.com/mjaschen/phpgeo/blob/master/src/Ellipsoid.php) +for a list of pre-defined ellipsoids. diff --git a/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/bounds-factory.png b/admin/vendor/mjaschen/phpgeo/docs/100_Geometries/bounds-factory.png new file mode 100644 index 0000000000000000000000000000000000000000..4662da89c4c12f0cc9cb2d8d4fd34ff487438cbf GIT binary patch literal 76244 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 + ? 'Mauna Kea and Haleakala share the same location.' + : 'Mauna Kea and Haleakala have different locations.'; + +$coordinate1 = new Coordinate(19.820664, -155.468066); // Mauna Kea Summit +$coordinate2 = new Coordinate(19.82365, -155.46905); // Gemini North Telescope + +echo $coordinate1->hasSameLocation($coordinate2, 1000) + ? 'Mauna Kea and the Gemini North Telescope are located within the same 1 km-radius.' + : 'Mauna Kea and the Gemini North Telescope are located more than 1 km apart.'; +``` + +The code above will produce the output below: + +``` plaintext +Mauna Kea and Haleakala have different locations. +Mauna Kea and the Gemini North Telescope are located within the same 1 km-radius. +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/320_Directions.md b/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/320_Directions.md new file mode 100644 index 000000000..cfe34db70 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/320_Directions.md @@ -0,0 +1,34 @@ +## Directions + +With the `Direction` class it's possible to determine if one point is north, east, south or west of another point. + +```php +pointIsNorthOf(point: $helsinki, compareAgainst: $berlin)) { + echo 'Helsinki is located north of Berlin.' . PHP_EOL; +} else { + echo 'Berlin is located north of Helsinki.' . PHP_EOL; +} + +if ($direction->pointIsEastOf(point: $rome, compareAgainst: $berlin)) { + echo 'Rome is located east of Berlin.' . PHP_EOL; +} else { + echo 'Berlin is located east of Rome.' . PHP_EOL; +} +``` + +The code above will produce the output below: + +``` plaintext +Helsinki is located north of Berlin. +Berlin is located east of Rome. +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/340_Intersections.md b/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/340_Intersections.md new file mode 100644 index 000000000..65e6da944 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/300_Comparisons/340_Intersections.md @@ -0,0 +1,14 @@ +## Intersection Checking + +It's possible to check if two geometries intersect each other. + +(Until this documentation page is finished, take a look into `IntersectionTest` – here you'll find some examples on how to use this feature.) + +The following combinations of geometries can be checked for intersection: + +| | Point | Line | Polyline | Polygon | +|----------|----------------------------------------------------------------|------|----------|-----------------------------------------------------------| +| Point | yes ([same location](/Comparisons/Same_Point_Comparison.html)) | no | no | yes ([point inside polygon](/Calculations/Geofence.html)) | +| Line | no | yes | yes | yes | +| Polyline | no | yes | yes | yes | +| Polygon | yes ([point inside polygon](/Calculations/Geofence.html)) | yes | yes | yes | diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/410_Distance_and_Length.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/410_Distance_and_Length.md new file mode 100644 index 000000000..91caa09d9 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/410_Distance_and_Length.md @@ -0,0 +1,121 @@ +# Distance and Length + +[TOC] + +## Distance Between Two Points (Vincenty's Formula) + +Use the calculator object directly: + +``` php +getDistance($coordinate1, $coordinate2); +``` + +The code above will produce the output below: + +``` plaintext +128130.850 +``` + +or call the `getDistance()` method of a `Coordinate` instance by injecting +a calculator instance: + +``` php +getDistance($coordinate2, new Vincenty()); +``` + +The code above will produce the output below: + +``` plaintext +128130.850 +``` + +## Distance Between Two Points (Haversine Formula) + +There exist different methods for calculating the distance between +two points. The [Haversine formula](https://en.wikipedia.org/wiki/Haversine_formula#Law) +is much faster than Vincenty's method but less precise: + +``` php +getDistance($coordinate2, new Haversine()); +``` + +The code above will produce the output below: + +``` plaintext +128384.515 +``` + +## Length of a Polyline + +*phpgeo* has a polyline implementation which can be used to calculate the +length of a GPS track or a route. A polyline consists of at least two points. +Points are instances of the `Coordinate` class. + +For more details about polylines/GPS tracks see the [`Polyline`](../Geometries/Polyline) section. + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$track->addPoint(new Coordinate(54.5, 12.5)); + +echo $track->getLength(new Vincenty()); +``` + +## Perimeter of a Polygon + +The perimeter is calculated as the sum of the length of all segments. +The result is given in meters. + +``` php +addPoint(new Coordinate(10, 10)); +$polygon->addPoint(new Coordinate(10, 20)); +$polygon->addPoint(new Coordinate(20, 20)); +$polygon->addPoint(new Coordinate(20, 10)); + +echo $polygon->getPerimeter(new Vincenty()); +``` + +The code above will produce the output below: + +``` plaintext +4355689.472 +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/420_Bearing_and_Destination.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/420_Bearing_and_Destination.md new file mode 100644 index 000000000..640aec1d1 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/420_Bearing_and_Destination.md @@ -0,0 +1,143 @@ +# Bearing and Destination + +[TOC] + +phpgeo can be used to calculate the bearing between two points and to +get a destination point for a given start point together with a bearing +angle and a distance. + +Multiple calculation algorithms are supported. Currently phpgeo provides +methods for calculations with a _spherical_ earth model and with an +_ellipsoidal_ model. The spherical calculations are very fast, compared +to the ellipsoidal methods. The ellipsoidal algorithms are a bit more +precise on the other hand. + +## Bearing between two points + +Given two points, it's possible to calculate the bearing angled between +those points. + +phpgeo can calculate the initial bearing (bearing as seen from the first +point) and the final bearing (bearing as seen approaching the destination +point). + +### Calculation with a spherical earth model + +``` php +calculateBearing($berlin, $london)); +var_dump($bearingCalculator->calculateFinalBearing($berlin, $london)); +$endTime = microtime(true); +printf("Time elapsed: %0.6f s\n", ($endTime - $startTime)); +``` + +The code above will produce the following output: + +``` plaintext +double(268.60722336693) +double(257.85494586285) +Time elapsed: 0.000285 s +``` + +### Calculation with an ellipsoidal earth model + +``` php +calculateBearing($berlin, $london)); +var_dump($bearingCalculator->calculateFinalBearing($berlin, $london)); +$endTime = microtime(true); +printf("Time elapsed: %0.6f s\n", ($endTime - $startTime)); +``` + +The code above will produce the following output: + +``` plaintext +double(268.62436347111) +double(257.87203657292) +Time elapsed: 0.000304 s +``` + +Both calculations finish in roughly the same time. One would expect the +second calculation to be clearly slower than the first one. It seems +the exit condition for the iteration is reached quite fast. There might +exist other conditions where the ellipsoidal calculation is noticeable +slower. + +## Destination point for given bearing and distance + +As an example, starting from Berlin, calculate the destination point in +56.1 km distance with an initial bearing of 153 degrees: + +``` php +calculateDestination($berlin, 153, 56100); +$destination2 = $bearingEllipsoidal->calculateDestination($berlin, 153, 56100); + +echo "Spherical: " . $destination1->format(new DecimalDegrees()) . PHP_EOL; +echo "Ellipsoidal: " . $destination2->format(new DecimalDegrees()) . PHP_EOL; +``` + +The code above will produce the output below: + +``` plaintext +Spherical: 52.04988 13.87628 +Ellipsoidal: 52.05020 13.87126 +``` + +Oh, look, what a [beautiful spot on earth](https://www.openstreetmap.org/?mlat=52.0499&mlon=13.8762#map=13/52.0499/13.8762) it is. ;-) + +## Final Bearing for a calculated destination + +*phpgeo* can calculate the final bearing angle for a given starting point, +an initial bearing, and the distance to the destination. + +``` php +calculateDestinationFinalBearing($berlin, 153, 56100); + +var_dump($finalBearing); +``` + +The code above will produce the output below: + +``` plaintext +float(153.29365182147) +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/425_Cardinal_Distance.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/425_Cardinal_Distance.md new file mode 100644 index 000000000..5d04b131f --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/425_Cardinal_Distance.md @@ -0,0 +1,70 @@ +# Cardinal Distance Between Two Points + +The distances how far you have to go to one cardinal direction and eventually to another to reach the second point +*P2* from the first one *P1* is called the Cardinal Distances. + +In the following example the Cardinal Distances are labeled *N* and *E:* + +![Cardinal Distance](cardinal-distance.png) + +[TOC] + +With *phpgeo* there are two ways to calculate the Cardinal Distances: + +## Using the Calculator Instance + +```php +getCardinalDirectionDistances($coordinate1, $coordinate2, $calculator); + +echo 'Cardinal Distances: north=' . $result->getNorth() +. ' m; east=' . $result->getEast() +. ' m; south=' . $result->getSouth( +. ' m; west=' . $result->getWest() . ' m.'; +``` + +The code above will produce the following output: + +``` +Cardinal Distances: north=98425.507 m; east=0 m; south=0 m; west=82268.492 m. +``` + +## Using the `getCardinalDirectionDistances()` method of a Coordinate instance + +```php +getCardinalDirection($point1, $point2); + +$result = $point1->getCardinalDirectionDistances($point2, new Vincenty()); + +echo 'Cardinal Distances: direction=' . $direction + . '; north=' . $result->getNorth() + . ' m; east=' . $result->getEast() + . ' m; south=' . $result->getSouth() + . ' m; west=' . $result->getWest() . ' m.'; +``` + +The code above will produce the following output: + +``` +Cardinal Distances: direction=north-east; north=0 m; east=0 m; south=8768.566 m; west=26969.504 m. +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/430_Perpendicular_Distance.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/430_Perpendicular_Distance.md new file mode 100644 index 000000000..a6af64d1d --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/430_Perpendicular_Distance.md @@ -0,0 +1,43 @@ +# Perpendicular Distance + +The _perpendicular distance_ is defined as the shortest distance between a point +a line (in the two-dimensional plane) respectively between a point and a +[great circle](https://en.wikipedia.org/wiki/Great_circle) on a spherical surface. + +With _phpgeo_ it is possible to calculate the perpendicular distance between a +point (instance of the [`Coordinate`](../Geometries/Coordinate) class) and a +Great Circle - which is defined by a [`Line`](../Geometries/Line). A line is +defined by a pair of coordinates. + +The distance between points *P* and *X* is the perpendicular distance in the following sketch: + +![perpendicular_distance](perpendicular-distance.png) + +## Example + +``` php +getPerpendicularDistance($point, $line) +); +``` + +The code above will produce the output below: + +``` plaintext +perpendicular distance: 936.7 meters +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/435_Distance_Between_Point_and_Line.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/435_Distance_Between_Point_and_Line.md new file mode 100644 index 000000000..e56bce11b --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/435_Distance_Between_Point_and_Line.md @@ -0,0 +1,46 @@ +# Distance Between a Point and a Line + +It's possible to calculate the shortest distance between a point and a +[`Line`](../Geometries/Line). As [`Polyline`](../Geometries/Polyline) +and [`Polygon`](../Geometries/Polygon) are also built upon the `Line` class +it's also possible to calculate distances from a point the polyline/polygon +by iterating over their segments. + +The following image explains how the distance is calcualated: *P* and *R* are +located in such a way that the nearest distance to the line is the distance between +*P*, *R* and the line end points. Point *Q* is nearer to the actual line than to +any of the end points, so the actual distance is the perpendicular distance between *Q* +and the line. + +![Point to Line Distance](point-to-line-distance.png) + +## Example + +``` php +getDistance($point, $line), + PHP_EOL +); +``` + +The code above will produce the output below: + +``` plaintext +Distance from point to line: 27164.1 meters +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/440_Geofence.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/440_Geofence.md new file mode 100644 index 000000000..5f5495bef --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/440_Geofence.md @@ -0,0 +1,40 @@ +# Geofence + +_phpgeo_ has a polygon implementation which can be used to determinate +if a geometry (point, line, polyline, polygon) is contained in it or not. +A polygon consists of at least three points. + +WARNING: The calculation gives wrong results if the polygons crosses +the 180/-180 degrees meridian. + +``` php +addPoint(new Coordinate(-12.085870,-77.016261)); +$geofence->addPoint(new Coordinate(-12.086373,-77.033813)); +$geofence->addPoint(new Coordinate(-12.102823,-77.030938)); +$geofence->addPoint(new Coordinate(-12.098669,-77.006476)); + +$outsidePoint = new Coordinate(-12.075452, -76.985079); +$insidePoint = new Coordinate(-12.092542, -77.021540); + +echo $geofence->contains($outsidePoint) + ? 'Point 1 is located inside the polygon' . PHP_EOL + : 'Point 1 is located outside the polygon' . PHP_EOL; + +echo $geofence->contains($insidePoint) + ? 'Point 2 is located inside the polygon' . PHP_EOL + : 'Point 2 is located outside the polygon' . PHP_EOL; +``` + +The code above will produce the output below: + +``` plaintext +Point 1 is located outside the polygon +Point 2 is located inside the polygon +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/cardinal-distance.png b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/cardinal-distance.png new file mode 100644 index 0000000000000000000000000000000000000000..9dca3f487e4da46727988bace0d8420fb42c8ba5 GIT binary patch literal 10254 zcmeHNd03N2w;w>DRhGJfqClaaB3lBANFbmEq%MFUtAG$7KqMrXgndhEMT-KpidJ^9 zfPgH@CIJ#GZUtGCeMy4sTY?CL9qt6X=xx7ypZnjv_krh0^1gFs&U@xJ=ggV&d->tC znThzuT^j)a;>W)+vIIaFUJA*7CJ29~7VI9t20YHnj$&te3gt%hQOCFwU9swcKE6;6 zfSy61FUHLqOObcQdg2IZg^6;8f;`S0tzfHViZt~##CqYr2_|9B1e;m81$(>cxGNaw zZ`2D!K?Oco3PwKA2TvfQ0?`URReZ1^tck zdL(xbl%>(J-v`4xw1O9f;)_Bc0s;cm0}iMYNuCG|9UUD6QWK%6sRnzfk%I^nOrRQp ztjJgKL5C5R>_)=*QgB3qJYOfqmFP!7D=0v@{O`)$-Tu_=>qo+`X?Ax*VDVTVEP+Bs zXsBx-KJJeV#QkLrf&4pM5I6*10=pwW=}y6U{G0B4$=|yBdJ!o^vKP_!PoqA0#Gm57 z4TNz2^N>J{?>}`mHT|!<`}lk^4Kl^p9|HILB79=g9}gf~1^HqTmRK^;kK~3m_J`;x zt^vo#1$7!1h{f9(;UK7FxEg2$4b8*I|0K5mNPHOik<^fgCz8%UKg7auYlHaUp^p1t zJh8SocZ%0X>i&|P!V*0BqCZrvN%;2R{rC=HO~An!Y5t|o?k^cyL0c2LBHvBcM%n+P z=+D(atr=)abcgmGSR3`1=(wTbX%f)`hletj#P;e~H zBghCtfxR@5nn*Pbq#9D&N)w6F)J7f9RzYf_eg|Z&H;f>63!oih`ry zv1@l9;^HWt^5O2oEgr`Y1{5Ac@I)&Fs<~r5Fn)N7g8peN$rnp-$GQ38F(hXr9GQY4 zxMB4W{7}Ny}TU2^E3EZE@IZr_9YQU+Z)4lX^{K&*Z!>i^#?3oZo*xd#kKX z@!@l_Br0ebKtVrW48iHP@kSD${SQh(jJX2Jz@=@B?;cVi{ww=FO zYs&O%*nesEohmbJ@RwjK*HhE?uYDDixf-!}{+USVrO{;2tlzSOLt5@RXLGSy{ zs?!f1H%y|xZ|l#=a|w{7^;ZOph#J&-HmC2sL4k?xbKh_5$pCEH%Kr#}_(W*{b1=-J?)1dj^8wTUU%(b!L^^1Hi)>k+U+81 ze13i;{&lm})01Uq<4#1UZ$VruO}%vc^Qhxl(ze0}yMJ=oW}Lo#^U)(mb_K5vGu3U> zO9aCfriW%0#`G9NI!^2evpuZDA8Hzk&FT zspK!J8uu1@)a^0|U*e6mw6yd+k1pqRdSj6woExu+Jz=p;%86o8+v}ZQ$$P07`@p_%@TBv?o4!~BdV~Jr zO}}FRb+L>*#PVx%YI7u;-d1-CUztiNRi!VC=13YWz3VLYjx|`Bdm$V0AY_(1uxCr^ z*Ppw1<oTu{iv556d|w5$?M$Xw5)$+Ee1=f!RC@u&(A3n_+PY=1F2O+x z>J8@iT3Hwi=)Ulx{h?d!Vc8=Cq^+v$YNC56jnAZ<9k)G0&vu{T+JoU&B9gLtLGSz1 zl(?0%EK-Bu>8uUN@jSN}oeZTYZ0)VMkS_qL>|U%s?On7`fec@kk&%(6MDypIRI$z5t?B+!XDG2L(>%pr?hC3}?;X$NvcY)osI>OCdkT_+N3%wnGV{+>E)-Nt z=nf^4gJ-!+u8^P=2>3R#=S|eNVR}()#FaMJ-@a;Dy^(+zQxu#NjHFdOU;2k zUq@t-8_-U)rHFl#PJS)cYO%vzo+)96d^(#O8<7FrZXrp%0=*_7ii@ChXSNo#v?bq} zF%hx42-p5KuUte-x*&Xcp`*}Kat~^HFoC$jnx$*w-u#k4q?c6=3a45YZ+K_2V{vvO zf?GCZmaJFiP)g{^%XcWvv&}yzBq|ZQH2FeQVs~J*xVB^9+e`Ed!2cUy=uj;3?x%m9 zj7n3AJ0UJEjt=2K{O%bXH zob2uGqhGMebJX$aEK-csBlW+$Zft>P(u(u)xQ&LAVUy3Ky2u{XsGeOeb5AAE(~Ys{ z4DYtQt^3UIOujV<@$r$8a&+w>!PG)rt+tt=VYRT7V`@mlw>)eDy?wc}jm{gs7aQz|tm5g3 zO7rsgVMZIv(|uPZWDd3OOAbuy?gNcF%Mc9o;LmOuW=X+Mgr$~NW*N2&pxZCy;&tQM zRVjnHo{MUdcYcNeYie2-G?diFD`mh~sg4wvIq226G(R=lc@0oRHc6?6zI!5yDC_@8 z9lFD)Eh9TO7e);^VENW|6`N2lImLkJ}KSH@b+7u%)@l+yuBx z6BSeS>M;?k%d;>hI~ftH`e6%253cRf8kLNgs}_|DJ?-RF8Q>|L`V%vFEceD<)AP*n zu2Q0#TVEcV#0nZ(UT9;`p=q$Q9Cu&@C?|l(LqP*^wjK@1Oq#uu6WZg|&rZ8nhYVJO zo?h8}&m@+Y*->eS;oSIs*@3;ynXwm8js}sHu4Apa&dZ~=DWUIw+pKtOH|gb<<_62t z4#Y|=Y|YJ-<#EpeS#hcvw&M{NZY`%LSe3DQ?_b`EgNxw`Et(pvQ<-o9dwztf2ABct z5Oma`CeD9$XEo9;@{)ndPho&&e^+B_~S>9Gxv7$-3{F zsDFv~*kw8T)bOkD%p_Lw6u6lLBK>Dr2h1m2iB0iZSHpRI*)*Def+)2G3sb~6Hm zoM4|hHi5UjJvyp?&+L2y2A~85#5g%tDBm};{(%aV*@cDh%;eUUtpbhqGYh>J;2KT% zwowb|O~n}*Nkalkx(x!6ns()0ZxaHT^Q@_cV#m~$ViVJp2o$c$zK=FD>co8whOJ5n zokdIZ5LS5L^UD+Tu1A)Ocd8dtR&p2ecdtGyO$WoF8<02aI*m6u(^op-BFU~0S6Rg- zv1>lk(%oDX%<48JYPE{*DVg}uuof+Gq~met7d07+D~ka{uVGeZ?1HdMzOuFT%)-*c zfn>qdB}bt(7yRIeAHLgwP~*|MpEcZCvaNNybVKLf@lz&xNB}4&0g=>;wCOh|rBv+- z3M=6W;VuvX`kMvBj)?lf-PSze5a;e?S=8jyttPRuOq#xT>w}#KJZ@e<0)EB^sQU*R z^vEM`(k0<$>}jyrA-B{cnmabumM>KWsxsxNFoO-HM63kRr;=zi8c9+RSV=?Wm$GvC ze`>Saz>$GT>977etsWNMMU5ehHfJ61tj9C;mZzH#<>QYu>xF=o5*%n!N*buK&ao*b z$ifo?cDD$)? z<`5b0E+M*otHt4Q0Nh7%1;yd)XIg9x-oI2dwpf~sjo^Q}Y5Jb^iSNaQffaHMpG8h7 z!mc1yDN2Vtc;y^$nOy@Ufk4A?I*WC?LK=^X77ro8k$n(`;nWy3ubmVN07aSb9VFI{ zZ1{MI*00wQSVv$TfprA_=LqcSB!*8Vyj^YB>6!SN77nWsG4^vvbnoXXOFlm!?*c3kwUdQc$yh)IUFzf|yl>?brG3xelch#VM z0uvUInXS#u-LU9}H8QM708owvku{Co-Hr|py1~=K@G!5(Yj-oYxOpO-Bnh)foDnd@ zw$uE)Ew(`>KqV?|z{XAx@=^Q@9(T8_tV}8Dh8Zf$JVjqp?_Cuvzl4zhgenM1D;w4# zs;sT8VPR>{2wz^FWwX<-HXxu-a792o?(Tq8Pny!%31McjciSVg4FGIE1`IFF_ewDW zVWrU!uQiqwz}mkyqvLQ!$q(IL5IPiPVR)eS_H800ukPy!Lc~?_E8bsGj8Temg+~f#T?2a7u{O9iwhHFUE^Ek| zxY#c6I3djzCdCA9`2<}JQLi`ks*6yb3rpi44JGzBK|D`mPUJS&2y}L21lUxBGFzC7 z(>veaNVy%d1AyVBL_zWO2g$@ z=TDSnK=MIf7}A{YA!n8ASVmf$8Ovv^6g8QZFLKLsvO}-HHw2on&hp2;PBUgNa|5oX z%{@bezi#LM&AmB^V3KOpW@cviWT##bsZ11Z|D7j5b>28*bp^6A#um*jEi)WQ|FG$X zkz#iaU+BHI^FUPEEJze8nh?4lPeST8ACh3OaIMwY z4?uyNEM}t*X&!P*;qwDsdHfN!&S5hq5{tFYEAKhPh>(?~c}O<47u;QjNge1zp5c&A z?-fNzIy-JNj+I42zSI|H=$PF)q{V8;qtk591r5M_p9snAkl4=v82^bsWO2MO0;ZeL zaf~)Au&@8O8<)j)Do_PL>b(o%$noQlvxk`NhlMYwlK7|B6YX*LVo;;44n(!6-YAtk zX{1Zl^hncej~sh$Fd@OFqH?lMJH9oKc`*X!v-U3`zwE^4sj{=PgL&ij+n&KB4{1=| z%M_=nUn{gTn3F3@QdiU3=bp=u8&LN!{cR#Kt8Lsc9$PU&4k}0nkxoG)>9_S?PZBF8 zpTl#~*>e#v#ZL`2AfkHTRZBvmEM!b0XXW4`ag}FK8rIe-Y2Y|HJi!j(Maa#_l~Tq! z$fcPg0Qjdi!-EQUXX@0?&?B0&&KNwJD}~iHWW*O4GIe!`mDuAlw<=4jOIQ2u^hqqW z9SAb4BdyCY-kqA(H?hk;t@Co`r7Pr~`>k+e$|0 zk~+_StficLrJkE5; zXDuH~X|3;r8-+yd(eE?^Bc3d2uTI6ZkcW!!{#kika<757v@Sg)EG$SA9t6!!0mBY_ z=u~ve)SwNgoS2W;-3Iw0NcBPzU?21Wa0N2g(8BdMbL$AKBk=zY0UBeX9!7To|9=7g d@5K0$9O`tApqY814YVB`H#RfM``YEZ{{V!|Dop?Y literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/index.md b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/index.md new file mode 100644 index 000000000..af687af45 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/index.md @@ -0,0 +1,3 @@ +# Calculations + +The following chapters describe the possibilities to do geographical calculations with *phpgeo,* e.g. length and distance calculations, determining bearings, etc. diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/perpendicular-distance.png b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/perpendicular-distance.png new file mode 100644 index 0000000000000000000000000000000000000000..49171e03aea3a2fd4e2e5631bbf73f417f255ce5 GIT binary patch literal 13745 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 R&kE%ft8aWL|DeN#{{yNn*RB8n literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/point-to-line-distance.png b/admin/vendor/mjaschen/phpgeo/docs/400_Calculations/point-to-line-distance.png new file mode 100644 index 0000000000000000000000000000000000000000..ff46a079f804299f3b0a477887494db68f109e6b GIT binary patch literal 22529 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 literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/510_Simplifying_a_Polyline_or_Polygon.md b/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/510_Simplifying_a_Polyline_or_Polygon.md new file mode 100644 index 000000000..621fabfae --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/510_Simplifying_a_Polyline_or_Polygon.md @@ -0,0 +1,91 @@ +# Simplifying a polyline/polygon + +[TOC] + +Polylines and polygons can be simplified to save storage space or bandwidth. + +_phpgeo_ provides two implementations for simplifying polyline/polygons. + +The first implementation uses the [_Ramer–Douglas–Peucker algorithm_](https://en.wikipedia.org/wiki/Ramer–Douglas–Peucker_algorithm) +(also known as _Douglas-Peucker algorithm_). The other implementation examines +the bearings of the segments and removes a segment when its bearing +angle is similar to the bearing angle of its predecessor segment. I named it +the _Delta-Bearing algorithm_. + +## Ramer-Douglas-Peucker Algorithm + +``` php +addPoint(new Coordinate(10.0, 10.0)); +$polyline->addPoint(new Coordinate(20.0, 20.0)); +$polyline->addPoint(new Coordinate(30.0, 10.0)); + +$processor = new SimplifyDouglasPeucker(1500000); + +$simplified = $processor->simplify($polyline); + +foreach ($simplified->getPoints() as $point) { + echo $point->format(new DecimalDegrees()) . PHP_EOL; +} +``` + +The example code will remove all points which perpendicular distance is less +than 1,500,000 meters (1,500 km) from the surrounding points. + +The code above produces the output below: + +``` plaintext +10.00000 10.00000 +30.00000 10.00000 +``` + +## Delta-Bearing Algorithm + +``` php +addPoint(new Coordinate(10.0, 10.0)); +$polyline->addPoint(new Coordinate(20.0, 20.0)); +$polyline->addPoint(new Coordinate(30.0, 10.0)); + +$processor = new SimplifyBearing(90); + +$simplified = $processor->simplify($polyline); + +foreach ($simplified->getPoints() as $point) { + echo $point->format(new DecimalDegrees()) . PHP_EOL; +} +``` + +The constructor argument for the `SimplifyBearing` class is the minimum +required angle in degrees between two adjacent polyline segments so that +no points will be removed. If the bearing angle difference is less that +the given value, the middle point will be removed from the resulting +polyline. + +The code above produces the output below: + +``` plaintext +10.00000 10.00000 +30.00000 10.00000 +``` + +The following image shows both a polyline and its simplified version. The +simplification was done with the Delta-Bearing Algorithm with a threshold angle +of 20 degrees. The original polyline is painted in blue, the simplified polyline +is magenta. + +![Delta-Bearing simplifying](simplify.png) diff --git a/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/index.md b/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/index.md new file mode 100644 index 000000000..2142ee762 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/index.md @@ -0,0 +1,5 @@ +# Transformations and Processing + +*phpgeo* provides tools for transforming and processing geometry instances. +It's possible to simplify a Polyline by removing unneeded points to save +storage space for example. diff --git a/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/simplify.png b/admin/vendor/mjaschen/phpgeo/docs/500_Transformations_and_Processing/simplify.png new file mode 100644 index 0000000000000000000000000000000000000000..3bcbfbe2ee5721a1d094fcb0b9e5fd15f83f584a GIT binary patch literal 193887 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 AK>z>% literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/100_Coordinates.md b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/100_Coordinates.md new file mode 100644 index 000000000..5ea51b69b --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/100_Coordinates.md @@ -0,0 +1,125 @@ +# Formatting Coordinates + +You can format a coordinate in different styles. + +## Decimal Degrees + +``` php +format(new DecimalDegrees()); +``` + +The code above produces the output below: + +``` plaintext +19.82066 -155.46807 +``` + +The separator string between latitude and longitude can be configured via +constructor argument, as well as the number of decimals (default value is +5 digits): + +``` php +format(new DecimalDegrees(', ', 3)); +``` + +The code above produces the output below: + +``` plaintext +19.821, -155.468 +``` + +## Degrees/Minutes/Seconds (DMS) + +``` php +format($formatter) . PHP_EOL; + +$formatter->setSeparator(', ') + ->useCardinalLetters(true) + ->setUnits(DMS::UNITS_ASCII); + +echo $coordinate->format($formatter) . PHP_EOL; +``` + +The code above produces the output below: + +``` plaintext +18° 54′ 41″ -155° 40′ 42″ +18° 54' 41" N, 155° 40' 42" W +``` + +## Decimal Minutes + +This format is commonly used in the Geocaching community. + +``` php +format($formatter) . PHP_EOL; + +$formatter->setSeparator(', ') + ->useCardinalLetters(true) + ->setUnits(DecimalMinutes::UNITS_ASCII); + +echo $coordinate->format($formatter) . PHP_EOL; +``` + +The code above produces the output below: + +``` plaintext +43° 37.386′ -070° 12.472′ +43° 37.386' N, 070° 12.472' W +``` + +## GeoJSON + +``` php +format(new GeoJSON()); +``` + +The code above produces the output below: + +``` json +{"type":"Point","coordinates":[-155.678268,18.911306]} +``` + +NOTE: Float values processed by `json_encode()` are affected by the ini-setting +[`serialize_precision`](https://secure.php.net/manual/en/ini.core.php#ini.serialize-precision). +You can change the number of decimal places in the JSON output by changing +that ini-option, e. g. with `ini_set('serialize_precision', 8)`. diff --git a/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/130_Polylines.md b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/130_Polylines.md new file mode 100644 index 000000000..02eedb590 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/130_Polylines.md @@ -0,0 +1,32 @@ +# Formatting Polylines + +You can format a polyline in different styles. + +## GeoJSON + +``` php +addPoint(new Coordinate(52.5, 13.5)); +$polyline->addPoint(new Coordinate(62.5, 14.5)); + +$formatter = new GeoJSON; + +echo $formatter->format($polyline); +``` + +The code above produces the output below: + +``` json +{"type":"LineString","coordinates":[[13.5,52.5],[14.5,62.5]]} +``` + +NOTE: Float values processed by `json_encode()` are affected by the ini-setting +[`serialize_precision`](https://secure.php.net/manual/en/ini.core.php#ini.serialize-precision). +You can change the number of decimal places in the JSON output by changing +that ini-option, e. g. with `ini_set('serialize_precision', 8)`. diff --git a/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/140_Polygons.md b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/140_Polygons.md new file mode 100644 index 000000000..c92cccc40 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/140_Polygons.md @@ -0,0 +1,34 @@ +# Formatting Polygons + +You can format a polygon in different styles. + +## GeoJSON + +``` php +addPoint(new Coordinate(10, 20)); +$polygon->addPoint(new Coordinate(20, 40)); +$polygon->addPoint(new Coordinate(30, 40)); +$polygon->addPoint(new Coordinate(30, 20)); + +$formatter = new GeoJSON; + +echo $formatter->format($polygon); +``` + +The code above produces the output below: + +``` json +{"type":"Polygon","coordinates":[[20,10],[40,20],[40,30],[20,30]]} +``` + +NOTE: Float values processed by `json_encode()` are affected by the ini-setting +[`serialize_precision`](https://secure.php.net/manual/en/ini.core.php#ini.serialize-precision). +You can change the number of decimal places in the JSON output by changing +that ini-option, e. g. with `ini_set('serialize_precision', 8)`. diff --git a/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/index.md b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/index.md new file mode 100644 index 000000000..f77afd420 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/600_Formatting_and_Output/index.md @@ -0,0 +1,5 @@ +# Formatting and Output + +*phpgeo* is able to output supported Geometry instances in many different +formats. You're able to provide your own Formatter classes for customization +of the output format. diff --git a/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/110_Coordinates_Parser.md b/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/110_Coordinates_Parser.md new file mode 100644 index 000000000..5b5946e42 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/110_Coordinates_Parser.md @@ -0,0 +1,53 @@ +# Coordinates Parser + +_phpgeo_ comes with a parser for several types of coordinate formats. +The parser works as a factory which creates an instance of the +`Coordinate` class. + +## Supported Formats + +**Decimal Degrees** with or without *cardinal letters*, +with or without a comma as separator, with or without +whitespace between values and cardinal letters. + +Examples of supported formats: + +- 52.5, 13.5 +- 52.5 13.5 +- -52.5 -13.5 +- 52.345 N, 13.456 E +- N52.345 E13.456 + +**Decimal Minutes** with or without cardinal letters, with +or without degree and minute signs, with or without a comma +as separator, with or without whitespace between values +and cardinal letters. + +Examples of supported formats: + +- 345, E13° 34.567 +- 45′ N, E13° 34.567′ E +- 5, 013 34.567 +- 45, -013 34.567 + +The [unit test](https://github.com/mjaschen/phpgeo/blob/master/tests/Location/Factory/CoordinateFactoryTest.php) +shows some more examples. + +## Example + + ```php +use Location\Factory\CoordinateFactory; +use Location\Formatter\Coordinate\DecimalDegrees; + +require_once __DIR__ . '/vendor/autoload.php'; + +$point = CoordinateFactory::fromString('52° 13.698′ 020° 58.536′'); + +echo $point->format(new DecimalDegrees()); +``` + +The code above produces the output below: + +``` plaintext + 52.22830 20.97560 +``` diff --git a/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/index.md b/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/index.md new file mode 100644 index 000000000..5e590c021 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/700_Parsing_and_Input/index.md @@ -0,0 +1,7 @@ +# Parsing and Input + +The constructor for the `Coordinate` class accepts a pair of float values +for creating an instance. Coordinates often come in formatted versions, +e.g. with cardinal letters, formatted in degrees, arc minutes, and arc +seconds and so on. *phpgeo* provides parsers for many formats which create +correctly instantiated `Coordinate` objects. diff --git a/admin/vendor/mjaschen/phpgeo/docs/900_Further_Reading.md b/admin/vendor/mjaschen/phpgeo/docs/900_Further_Reading.md new file mode 100644 index 000000000..41b4babda --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/900_Further_Reading.md @@ -0,0 +1,6 @@ +# Further Reading / Sources + +- [Movable Type Scripts](https://www.movable-type.co.uk/scripts/latlong.html) +- [Aviation Formulary V1.24 by Ed Williams](https://www.edwilliams.org/ftp/avsig/avform.txt) +- [Perpendicular Distance Calculator](https://biodiversityinformatics.amnh.org/open_source/pdc/index.html) ([Github](https://github.com/persts/GeographicDistanceTools)) +- [W. Randolph Franklin, PNPOLY - Point Inclusion in Polygon Test](https://wrfranklin.org/Research/Short_Notes/pnpoly.html) diff --git a/admin/vendor/mjaschen/phpgeo/docs/BoundsFactory.afdesign b/admin/vendor/mjaschen/phpgeo/docs/BoundsFactory.afdesign new file mode 100644 index 0000000000000000000000000000000000000000..c763728fa4ec7ee85397aeaab416fe67c5adad08 GIT binary patch literal 16633 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 E598uQ%m4rY literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/Cardinal_Distance.afdesign b/admin/vendor/mjaschen/phpgeo/docs/Cardinal_Distance.afdesign new file mode 100644 index 0000000000000000000000000000000000000000..76b6232e193c53be3e7a948d409d1c296fb3be82 GIT binary patch literal 10492 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 R4^03-NnTy9PR1ha{{V=>jy(VX literal 0 HcmV?d00001 diff --git a/admin/vendor/mjaschen/phpgeo/docs/config.json b/admin/vendor/mjaschen/phpgeo/docs/config.json new file mode 100644 index 000000000..f5b9d6db4 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/config.json @@ -0,0 +1,25 @@ +{ + "title": "phpgeo", + "tagline": "A Simple Yet Powerful Geo Library for PHP", + "author": "Marcus Jaschen", + "format": "html", + "timezone": "Europe/Berlin", + "html": { + "theme": "daux-red", + "breadcrumbs": true, + "breadcrumb_separator": "Chevrons", + "toggle_code": true, + "date_modified": true, + "inherit_index": true, + "search": true, + "repo": "mjaschen/phpgeo", + "edit_on_github": "mjaschen/phpgeo/blob/master/docs", + "piwik_analytics": "metrics.m11n.de", + "piwik_analytics_id": "15", + "links": { + "Download": "https://github.com/mjaschen/phpgeo/archive/master.zip", + "GitHub Repo": "https://github.com/mjaschen/phpgeo", + "Help/Support/Bugs": "https://github.com/mjaschen/phpgeo/issues" + } + } +} diff --git a/admin/vendor/mjaschen/phpgeo/docs/intersection-polyline-simple.dxf b/admin/vendor/mjaschen/phpgeo/docs/intersection-polyline-simple.dxf new file mode 100644 index 000000000..52182377e --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/docs/intersection-polyline-simple.dxf @@ -0,0 +1,3400 @@ +999 +dxfrw 0.6.3 + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1021 + 9 +$DWGCODEPAGE + 3 +ANSI_1252 + 9 +$INSBASE + 10 +0 + 20 +0 + 30 +0 + 9 +$EXTMIN + 10 +-8 + 20 +-5 + 30 +0 + 9 +$EXTMAX + 10 +21 + 20 +24 + 30 +0 + 9 +$LIMMIN + 10 +0 + 20 +0 + 9 +$LIMMAX + 10 +420 + 20 +297 + 9 +$ORTHOMODE + 70 + 0 + 9 +$REGENMODE + 70 + 1 + 9 +$FILLMODE + 70 + 1 + 9 +$QTEXTMODE + 70 + 0 + 9 +$MIRRTEXT + 70 + 0 + 9 +$LTSCALE + 40 +1 + 9 +$ATTMODE + 70 + 0 + 9 +$TEXTSIZE + 40 +2.5 + 9 +$TRACEWID + 40 +15.68 + 9 +$TEXTSTYLE + 7 +STANDARD + 9 +$CLAYER + 8 +Bounds 5 + 9 +$CELTYPE + 6 +BYLAYER + 9 +$CECOLOR + 62 + 256 + 9 +$CELTSCALE + 40 +1 + 9 +$DISPSILH + 70 + 0 + 9 +$DIMSCALE + 40 +2.5 + 9 +$DIMASZ + 40 +2.5 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMDLI + 40 +3.75 + 9 +$DIMRND + 40 +0 + 9 +$DIMDLE + 40 +0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMTP + 40 +0 + 9 +$DIMTM + 40 +0 + 9 +$DIMTXT + 40 +2.5 + 9 +$DIMCEN + 40 +2.5 + 9 +$DIMTSZ + 40 +0 + 9 +$DIMTOL + 70 + 0 + 9 +$DIMLIM + 70 + 0 + 9 +$DIMTIH + 70 + 0 + 9 +$DIMTOH + 70 + 0 + 9 +$DIMSE1 + 70 + 0 + 9 +$DIMSE2 + 70 + 0 + 9 +$DIMTAD + 70 + 1 + 9 +$DIMZIN + 70 + 8 + 9 +$DIMBLK + 1 + + 9 +$DIMASO + 70 + 1 + 9 +$DIMSHO + 70 + 1 + 9 +$DIMPOST + 1 + + 9 +$DIMAPOST + 1 + + 9 +$DIMALT + 70 + 0 + 9 +$DIMALTD + 70 + 3 + 9 +$DIMALTF + 40 +0.03937 + 9 +$DIMLFAC + 40 +1 + 9 +$DIMTOFL + 70 + 1 + 9 +$DIMTVP + 40 +0 + 9 +$DIMTIX + 70 + 0 + 9 +$DIMSOXD + 70 + 0 + 9 +$DIMSAH + 70 + 0 + 9 +$DIMBLK1 + 1 + + 9 +$DIMBLK2 + 1 + + 9 +$DIMSTYLE + 2 +STANDARD + 9 +$DIMCLRD + 70 + 0 + 9 +$DIMCLRE + 70 + 0 + 9 +$DIMCLRT + 70 + 0 + 9 +$DIMTFAC + 40 +1 + 9 +$DIMGAP + 40 +0.625 + 9 +$DIMJUST + 70 + 0 + 9 +$DIMSD1 + 70 + 0 + 9 +$DIMSD2 + 70 + 0 + 9 +$DIMTOLJ + 70 + 0 + 9 +$DIMTZIN + 70 + 8 + 9 +$DIMALTZ + 70 + 0 + 9 +$DIMALTTZ + 70 + 0 + 9 +$DIMUPT + 70 + 0 + 9 +$DIMDEC + 70 + 2 + 9 +$DIMTDEC + 70 + 2 + 9 +$DIMALTU + 70 + 2 + 9 +$DIMALTTD + 70 + 3 + 9 +$DIMTXSTY + 7 +STANDARD + 9 +$DIMAUNIT + 70 + 0 + 9 +$DIMADEC + 70 + 0 + 9 +$DIMALTRND + 40 +0 + 9 +$DIMAZIN + 70 + 0 + 9 +$DIMDSEP + 70 + 44 + 9 +$DIMATFIT + 70 + 3 + 9 +$DIMFRAC + 70 + 0 + 9 +$DIMLDRBLK + 1 +STANDARD + 9 +$DIMLUNIT + 70 + 2 + 9 +$DIMLWD + 70 + -2 + 9 +$DIMLWE + 70 + -2 + 9 +$DIMTMOVE + 70 + 0 + 9 +$DIMFXL + 40 +1 + 9 +$DIMFXLON + 70 + 0 + 9 +$DIMJOGANG + 40 +0.7854 + 9 +$DIMTFILL + 70 + 0 + 9 +$DIMTFILLCLR + 70 + 0 + 9 +$DIMARCSYM + 70 + 0 + 9 +$DIMLTYPE + 6 + + 9 +$DIMLTEX1 + 6 + + 9 +$DIMLTEX2 + 6 + + 9 +$LUNITS + 70 + 2 + 9 +$LUPREC + 70 + 4 + 9 +$SKETCHINC + 40 +1 + 9 +$FILLETRAD + 40 +0 + 9 +$AUNITS + 70 + 0 + 9 +$AUPREC + 70 + 2 + 9 +$MENU + 1 +. + 9 +$ELEVATION + 40 +0 + 9 +$PELEVATION + 40 +0 + 9 +$THICKNESS + 40 +0 + 9 +$LIMCHECK + 70 + 0 + 9 +$CHAMFERA + 40 +0 + 9 +$CHAMFERB + 40 +0 + 9 +$CHAMFERC + 40 +0 + 9 +$CHAMFERD + 40 +0 + 9 +$SKPOLY + 70 + 0 + 9 +$USRTIMER + 70 + 1 + 9 +$ANGBASE + 50 +0 + 9 +$ANGDIR + 70 + 0 + 9 +$PDMODE + 70 + 34 + 9 +$PDSIZE + 40 +0 + 9 +$PLINEWID + 40 +0 + 9 +$SPLFRAME + 70 + 0 + 9 +$SPLINETYPE + 70 + 2 + 9 +$SPLINESEGS + 70 + 8 + 9 +$HANDSEED + 5 +20000 + 9 +$SURFTAB1 + 70 + 6 + 9 +$SURFTAB2 + 70 + 6 + 9 +$SURFTYPE + 70 + 6 + 9 +$SURFU + 70 + 6 + 9 +$SURFV + 70 + 6 + 9 +$UCSBASE + 2 + + 9 +$UCSNAME + 2 + + 9 +$UCSORG + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSXDIR + 10 +1 + 20 +0 + 30 +0 + 9 +$UCSYDIR + 10 +0 + 20 +1 + 30 +0 + 9 +$UCSORTHOREF + 2 + + 9 +$UCSORTHOVIEW + 70 + 0 + 9 +$UCSORGTOP + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGBOTTOM + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGLEFT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGRIGHT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGFRONT + 10 +0 + 20 +0 + 30 +0 + 9 +$UCSORGBACK + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSBASE + 2 + + 9 +$PUCSNAME + 2 + + 9 +$PUCSORG + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSXDIR + 10 +1 + 20 +0 + 30 +0 + 9 +$PUCSYDIR + 10 +0 + 20 +1 + 30 +0 + 9 +$PUCSORTHOREF + 2 + + 9 +$PUCSORTHOVIEW + 70 + 0 + 9 +$PUCSORGTOP + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGBOTTOM + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGLEFT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGRIGHT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGFRONT + 10 +0 + 20 +0 + 30 +0 + 9 +$PUCSORGBACK + 10 +0 + 20 +0 + 30 +0 + 9 +$USERI1 + 70 + 0 + 9 +$USERI2 + 70 + 0 + 9 +$USERI3 + 70 + 0 + 9 +$USERI4 + 70 + 0 + 9 +$USERI5 + 70 + 0 + 9 +$USERR1 + 40 +0 + 9 +$USERR2 + 40 +0 + 9 +$USERR3 + 40 +0 + 9 +$USERR4 + 40 +0 + 9 +$USERR5 + 40 +0 + 9 +$WORLDVIEW + 70 + 1 + 9 +$SHADEDGE + 70 + 3 + 9 +$SHADEDIF + 70 + 70 + 9 +$TILEMODE + 70 + 1 + 9 +$MAXACTVP + 70 + 64 + 9 +$PINSBASE + 10 +0 + 20 +0 + 30 +0 + 9 +$PLIMCHECK + 70 + 0 + 9 +$PEXTMIN + 10 +0 + 20 +0 + 30 +0 + 9 +$PEXTMAX + 10 +0 + 20 +0 + 30 +0 + 9 +$PLIMMIN + 10 +0 + 20 +0 + 9 +$PLIMMAX + 10 +297 + 20 +210 + 9 +$UNITMODE + 70 + 0 + 9 +$VISRETAIN + 70 + 1 + 9 +$PLINEGEN + 70 + 0 + 9 +$PSLTSCALE + 70 + 1 + 9 +$TREEDEPTH + 70 + 3020 + 9 +$CMLSTYLE + 2 +Standard + 9 +$CMLJUST + 70 + 0 + 9 +$CMLSCALE + 40 +20 + 9 +$PROXYGRAPHICS + 70 + 1 + 9 +$MEASUREMENT + 70 + 1 + 9 +$CELWEIGHT +370 + -1 + 9 +$ENDCAPS +280 + 0 + 9 +$JOINSTYLE +280 + 0 + 9 +$LWDISPLAY +290 + 0 + 9 +$INSUNITS + 70 + 0 + 9 +$HYPERLINKBASE + 1 + + 9 +$STYLESHEET + 1 + + 9 +$XEDIT +290 + 1 + 9 +$CEPSNTYPE +380 + 0 + 9 +$PSTYLEMODE +290 + 1 + 9 +$EXTNAMES +290 + 1 + 9 +$PSVPSCALE + 40 +0 + 9 +$OLESTARTUP +290 + 0 + 9 +$SORTENTS +280 + 127 + 9 +$INDEXCTL +280 + 0 + 9 +$HIDETEXT +280 + 1 + 9 +$XCLIPFRAME +290 + 0 + 9 +$HALOGAP +280 + 0 + 9 +$OBSCOLOR + 70 + 257 + 9 +$OBSLTYPE +280 + 0 + 9 +$INTERSECTIONDISPLAY +280 + 0 + 9 +$INTERSECTIONCOLOR + 70 + 257 + 9 +$DIMASSOC +280 + 1 + 9 +$PROJECTNAME + 1 + + 9 +$CAMERADISPLAY +290 + 0 + 9 +$LENSLENGTH + 40 +50 + 9 +$CAMERAHEIGHT + 40 +0 + 9 +$STEPSPERSEC + 40 +2 + 9 +$STEPSIZE + 40 +50 + 9 +$3DDWFPREC + 40 +2 + 9 +$PSOLWIDTH + 40 +5 + 9 +$PSOLHEIGHT + 40 +80 + 9 +$LOFTANG1 + 40 +1.570796326794897 + 9 +$LOFTANG2 + 40 +1.570796326794897 + 9 +$LOFTMAG1 + 40 +0 + 9 +$LOFTMAG2 + 40 +0 + 9 +$LOFTPARAM + 70 + 7 + 9 +$LOFTNORMALS +280 + 1 + 9 +$LATITUDE + 40 +1 + 9 +$LONGITUDE + 40 +1 + 9 +$NORTHDIRECTION + 40 +0 + 9 +$TIMEZONE + 70 +-8000 + 9 +$LIGHTGLYPHDISPLAY +280 + 1 + 9 +$TILEMODELIGHTSYNCH +280 + 1 + 9 +$SOLIDHIST +280 + 1 + 9 +$SHOWHIST +280 + 1 + 9 +$DWFFRAME +280 + 2 + 9 +$DGNFRAME +280 + 0 + 9 +$REALWORLDSCALE +290 + 1 + 9 +$INTERFERECOLOR + 62 + 1 + 9 +$CSHADOW +280 + 0 + 9 +$SHADOWPLANELOCATION + 40 +0 + 0 +ENDSEC + 0 +SECTION + 2 +CLASSES + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +VPORT + 5 +31 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*ACTIVE + 70 + 0 + 10 +0 + 20 +0 + 11 +1 + 21 +1 + 12 +23.51971990919577 + 22 +14.78994814505351 + 13 +0 + 23 +0 + 14 +10 + 24 +10 + 15 +10 + 25 +10 + 16 +0 + 26 +0 + 36 +1 + 17 +0 + 27 +0 + 37 +0 + 40 +44.97391346348288 + 41 +1.720970537261698 + 42 +50 + 43 +0 + 44 +0 + 50 +0 + 51 +0 + 71 + 0 + 72 + 100 + 73 + 1 + 74 + 3 + 75 + 0 + 76 + 1 + 77 + 0 + 78 + 0 +281 + 0 + 65 + 1 +110 +0 +120 +0 +130 +0 +111 +1 +121 +0 +131 +0 +112 +0 +122 +1 +132 +0 + 79 + 0 +146 +0 +348 +10020 + 60 + 7 + 61 + 5 +292 +1 +282 + 1 +141 +0 +142 +0 + 63 + 250 +421 +3358443 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +330 +0 +100 +AcDbSymbolTable + 70 + 4 + 0 +LTYPE + 5 +14 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +15 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 + 0 + 3 + + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +16 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +Continuous + 70 + 0 + 3 +Solid line + 72 + 65 + 73 + 0 + 40 +0 + 0 +LTYPE + 5 +32 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT + 70 + 0 + 3 +Dot . . . . . . . . . . . . . . . . . . . . . . + 72 + 65 + 73 + 2 + 40 +6.35 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +33 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOTTINY + 70 + 0 + 3 +Dot (.15x) ..................................... + 72 + 65 + 73 + 2 + 40 +0.9525 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +34 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT2 + 70 + 0 + 3 +Dot (.5x) ..................................... + 72 + 65 + 73 + 2 + 40 +3.175 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +35 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOTX2 + 70 + 0 + 3 +Dot (2x) . . . . . . . . . . . . . + 72 + 65 + 73 + 2 + 40 +12.7 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +36 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED + 70 + 0 + 3 +Dashed _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +19.05 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +37 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHEDTINY + 70 + 0 + 3 +Dashed (.15x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +2.8575 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +38 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED2 + 70 + 0 + 3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 + 65 + 73 + 2 + 40 +9.524999999999999 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +39 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHEDX2 + 70 + 0 + 3 +Dashed (2x) ____ ____ ____ ____ ____ ___ + 72 + 65 + 73 + 2 + 40 +38.09999999999999 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +3A +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT + 70 + 0 + 3 +Dash dot __ . __ . __ . __ . __ . __ . __ . __ + 72 + 65 + 73 + 4 + 40 +25.4 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +3B +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOTTINY + 70 + 0 + 3 +Dash dot (.15x) _._._._._._._._._._._._._._._. + 72 + 65 + 73 + 4 + 40 +3.81 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +3C +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT2 + 70 + 0 + 3 +Dash dot (.5x) _._._._._._._._._._._._._._._. + 72 + 65 + 73 + 4 + 40 +12.7 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +3D +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOTX2 + 70 + 0 + 3 +Dash dot (2x) ____ . ____ . ____ . ___ + 72 + 65 + 73 + 4 + 40 +50.8 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +3E +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE + 70 + 0 + 3 +Divide ____ . . ____ . . ____ . . ____ . . ____ + 72 + 65 + 73 + 6 + 40 +31.75 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +3F +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDETINY + 70 + 0 + 3 +Divide (.15x) __..__..__..__..__..__..__..__.._ + 72 + 65 + 73 + 6 + 40 +4.7625 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +40 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE2 + 70 + 0 + 3 +Divide (.5x) __..__..__..__..__..__..__..__.._ + 72 + 65 + 73 + 6 + 40 +15.875 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +41 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDEX2 + 70 + 0 + 3 +Divide (2x) ________ . . ________ . . _ + 72 + 65 + 73 + 6 + 40 +63.5 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +42 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER + 70 + 0 + 3 +Border __ __ . __ __ . __ __ . __ __ . __ __ . + 72 + 65 + 73 + 6 + 40 +44.45 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +12.7 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +43 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDERTINY + 70 + 0 + 3 +Border (.15x) __.__.__.__.__.__.__.__.__.__.__. + 72 + 65 + 73 + 6 + 40 +6.6675 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +1.905 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +44 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER2 + 70 + 0 + 3 +Border (.5x) __.__.__.__.__.__.__.__.__.__.__. + 72 + 65 + 73 + 6 + 40 +22.225 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +6.35 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +45 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDERX2 + 70 + 0 + 3 +Border (2x) ____ ____ . ____ ____ . ___ + 72 + 65 + 73 + 6 + 40 +88.89999999999999 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +25.4 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +0 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +LTYPE + 5 +46 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER + 70 + 0 + 3 +Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ + 72 + 65 + 73 + 4 + 40 +50.8 + 49 +31.75 + 74 + 0 + 49 +-6.35 + 74 + 0 + 49 +6.35 + 74 + 0 + 49 +-6.35 + 74 + 0 + 0 +LTYPE + 5 +47 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTERTINY + 70 + 0 + 3 +Center (.15x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 + 65 + 73 + 4 + 40 +7.619999999999999 + 49 +4.7625 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 49 +0.9525 + 74 + 0 + 49 +-0.9525 + 74 + 0 + 0 +LTYPE + 5 +48 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER2 + 70 + 0 + 3 +Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 + 65 + 73 + 4 + 40 +28.575 + 49 +19.05 + 74 + 0 + 49 +-3.175 + 74 + 0 + 49 +3.175 + 74 + 0 + 49 +-3.175 + 74 + 0 + 0 +LTYPE + 5 +49 +330 +5 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTERX2 + 70 + 0 + 3 +Center (2x) ________ __ ________ __ _____ + 72 + 65 + 73 + 4 + 40 +101.6 + 49 +63.5 + 74 + 0 + 49 +-12.7 + 74 + 0 + 49 +12.7 + 74 + 0 + 49 +-12.7 + 74 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +LAYER + 5 +10 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 + 0 + 62 + 7 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4A +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 1 + 70 + 0 + 62 + 16 +420 +8388608 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4B +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 2 + 70 + 0 + 62 + 56 +420 +8421376 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4C +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 3 + 70 + 0 + 62 + 96 +420 +32768 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4D +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 4 + 70 + 0 + 62 + 136 +420 +32896 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4E +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Bounds 5 + 70 + 0 + 62 + 176 +420 + 128 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +4F +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 1 + 70 + 0 + 62 + 1 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +50 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 2 + 70 + 0 + 62 + 2 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +51 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 3 + 70 + 0 + 62 + 3 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +52 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 4 + 70 + 0 + 62 + 4 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +LAYER + 5 +53 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +Line 5 + 70 + 0 + 62 + 5 + 6 +CONTINUOUS +370 + 0 +390 +F + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +330 +0 +100 +AcDbSymbolTable + 70 + 3 + 0 +STYLE + 5 +54 +330 +2 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 + 0 + 40 +0 + 41 +1 + 50 +0 + 71 + 0 + 42 +1 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +330 +0 +100 +AcDbSymbolTable + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +330 +0 +100 +AcDbSymbolTable + 70 + 1 + 0 +APPID + 5 +12 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 + 0 + 0 +APPID + 5 +55 +330 +9 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +LibreCad + 70 + 0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +330 +0 +100 +AcDbSymbolTable + 70 + 1 +100 +AcDbDimStyleTable + 71 + 1 + 0 +DIMSTYLE +105 +56 +330 +A +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 70 + 0 + 40 +1 + 41 +2.5 + 42 +0.625 + 43 +0.38 + 44 +1.25 + 45 +0 + 46 +0 + 47 +0 + 48 +0 + 49 +1 +140 +2.5 +141 +0.09 +142 +0 +143 +25.4 +144 +1 +145 +0 +146 +1 +147 +0.625 +148 +0 + 71 + 0 + 72 + 0 + 73 + 0 + 74 + 1 + 75 + 0 + 76 + 0 + 77 + 0 + 78 + 1 + 79 + 0 +170 + 0 +171 + 2 +172 + 0 +173 + 0 +174 + 0 +175 + 0 +176 + 0 +177 + 0 +178 + 0 +179 + 2 +271 + 4 +272 + 4 +273 + 2 +274 + 2 +275 + 0 +276 + 0 +277 + 2 +278 + 0 +279 + 0 +280 + 0 +281 + 0 +282 + 0 +283 + 1 +284 + 0 +285 + 0 +286 + 0 +288 + 0 +289 + 3 +340 +standard +341 + +371 + -2 +372 + -2 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +330 +0 +100 +AcDbSymbolTable + 70 + 2 + 0 +BLOCK_RECORD + 5 +1F +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space + 70 + 0 +280 + 1 +281 + 0 + 0 +BLOCK_RECORD + 5 +1E +330 +1 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space + 70 + 0 +280 + 1 +281 + 0 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +20 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 + 0 + 10 +0 + 20 +0 + 30 +0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +21 +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +1C +330 +1B +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 + 0 + 10 +0 + 20 +0 + 30 +0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +1D +330 +1F +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LINE + 5 +57 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-4 + 20 +-2 + 11 +5 + 21 +2 + 0 +LINE + 5 +58 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +5 + 20 +2 + 11 +-1 + 21 +7 + 0 +LINE + 5 +59 +100 +AcDbEntity + 8 +Line 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-1 + 20 +7 + 11 +-3 + 21 +4 + 0 +LINE + 5 +5A +100 +AcDbEntity + 8 +Line 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-8 + 20 +3 + 11 +-5 + 21 +-5 + 0 +LINE + 5 +5B +100 +AcDbEntity + 8 +Line 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-5 + 20 +-5 + 11 +4 + 21 +-3 + 0 +LINE + 5 +5C +100 +AcDbEntity + 8 +Line 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +15 + 20 +18 + 11 +21 + 21 +14 + 0 +LINE + 5 +5D +100 +AcDbEntity + 8 +Line 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +21 + 20 +14 + 11 +11 + 21 +13 + 0 +LWPOLYLINE + 5 +5E +100 +AcDbEntity + 8 +Bounds 1 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +-4 + 20 +-2 + 10 +5 + 20 +-2 + 10 +5 + 20 +7 + 10 +-4 + 20 +7 + 0 +LWPOLYLINE + 5 +5F +100 +AcDbEntity + 8 +Bounds 2 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +4 + 20 +-5 + 10 +-8 + 20 +-5 + 10 +-8 + 20 +3 + 10 +4 + 20 +3 + 0 +LWPOLYLINE + 5 +60 +100 +AcDbEntity + 8 +Bounds 3 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +11 + 20 +13 + 10 +21 + 20 +13 + 10 +21 + 20 +18 + 10 +11 + 20 +18 + 0 +LINE + 5 +61 +100 +AcDbEntity + 8 +Line 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-6 + 20 +9 + 11 +-1 + 21 +5 + 0 +LINE + 5 +62 +100 +AcDbEntity + 8 +Line 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +-1 + 20 +5 + 11 +1 + 21 +10 + 0 +LWPOLYLINE + 5 +63 +100 +AcDbEntity + 8 +Bounds 4 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +1 + 20 +10 + 10 +-6 + 20 +10 + 10 +-6 + 20 +5 + 10 +1 + 20 +5 + 0 +LINE + 5 +64 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +13 + 20 +24 + 11 +9 + 21 +22 + 0 +LINE + 5 +65 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +8 + 20 +15 + 11 +14 + 21 +20 + 0 +LINE + 5 +66 +100 +AcDbEntity + 8 +Line 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbLine + 10 +14 + 20 +20 + 11 +13 + 21 +24 + 0 +LWPOLYLINE + 5 +67 +100 +AcDbEntity + 8 +Bounds 5 + 6 +ByLayer + 62 + 256 +370 + -1 +100 +AcDbPolyline + 90 + 4 + 70 + 1 + 43 +0 + 10 +8 + 20 +15 + 10 +14 + 20 +15 + 10 +14 + 20 +24 + 10 +8 + 20 +24 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +330 +0 +100 +AcDbDictionary +281 + 1 + 3 +ACAD_GROUP +350 +D + 0 +DICTIONARY + 5 +D +330 +C +100 +AcDbDictionary +281 + 1 + 0 +PLOTSETTINGS + 5 +68 +100 +AcDbPlotSettings + 6 +1x1 + 40 +0 + 41 +0 + 42 +0 + 43 +0 + 0 +ENDSEC + 0 +EOF diff --git a/admin/vendor/mjaschen/phpgeo/phpcs.xml.dist b/admin/vendor/mjaschen/phpgeo/phpcs.xml.dist new file mode 100644 index 000000000..97f8cf691 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/phpcs.xml.dist @@ -0,0 +1,121 @@ + + + + This standard requires PHP_CodeSniffer >= 3.4. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/admin/vendor/mjaschen/phpgeo/phpunit.xml b/admin/vendor/mjaschen/phpgeo/phpunit.xml new file mode 100644 index 000000000..812e73a7c --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/phpunit.xml @@ -0,0 +1,14 @@ + + + + + src + + + + + tests/Location/ + tests/Regression/ + + + diff --git a/admin/vendor/mjaschen/phpgeo/psalm.xml b/admin/vendor/mjaschen/phpgeo/psalm.xml new file mode 100644 index 000000000..0ae3aefb3 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/psalm.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingEllipsoidal.php b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingEllipsoidal.php new file mode 100644 index 000000000..01f908c74 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingEllipsoidal.php @@ -0,0 +1,256 @@ + + */ +class BearingEllipsoidal implements BearingInterface +{ + /** + * This method calculates the initial bearing between the + * two points. + * + * If the two points share the same location, the bearing + * value will be 0.0. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float Bearing Angle + */ + public function calculateBearing(Coordinate $point1, Coordinate $point2): float + { + if ($point1->hasSameLocation($point2)) { + return 0.0; + } + + return $this->inverseVincenty($point1, $point2)->getBearingInitial(); + } + + /** + * Calculates the final bearing between the two points. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float + */ + public function calculateFinalBearing(Coordinate $point1, Coordinate $point2): float + { + return $this->inverseVincenty($point1, $point2)->getBearingFinal(); + } + + /** + * Calculates a destination point for the given point, bearing angle, + * and distance. + * + * @param Coordinate $point + * @param float $bearing the bearing angle between 0 and 360 degrees + * @param float $distance the distance to the destination point in meters + * + * @return Coordinate + */ + public function calculateDestination(Coordinate $point, float $bearing, float $distance): Coordinate + { + return $this->directVincenty($point, $bearing, $distance)->getDestination(); + } + + /** + * Calculates the final bearing angle for a destination point. + * The method expects a starting point point, the bearing angle, + * and the distance to destination. + * + * @param Coordinate $point + * @param float $bearing + * @param float $distance + * + * @return float + * + * @throws NotConvergingException + */ + public function calculateDestinationFinalBearing(Coordinate $point, float $bearing, float $distance): float + { + return $this->directVincenty($point, $bearing, $distance)->getBearingFinal(); + } + + /** + * @param Coordinate $point + * @param float $bearing + * @param float $distance + * + * @return DirectVincentyBearing + * + * @throws NotConvergingException + */ + private function directVincenty(Coordinate $point, float $bearing, float $distance): DirectVincentyBearing + { + $phi1 = deg2rad($point->getLat()); + $lambda1 = deg2rad($point->getLng()); + $alpha1 = deg2rad($bearing); + + $a = $point->getEllipsoid()->getA(); + $b = $point->getEllipsoid()->getB(); + $f = 1 / $point->getEllipsoid()->getF(); + + $sinAlpha1 = sin($alpha1); + $cosAlpha1 = cos($alpha1); + + $tanU1 = (1 - $f) * tan($phi1); + $cosU1 = 1 / sqrt(1 + $tanU1 * $tanU1); + $sinU1 = $tanU1 * $cosU1; + $sigma1 = atan2($tanU1, $cosAlpha1); + $sinAlpha = $cosU1 * $sinAlpha1; + $cosSquAlpha = 1 - $sinAlpha * $sinAlpha; + $uSq = $cosSquAlpha * ($a * $a - $b * $b) / ($b * $b); + $A = 1 + $uSq / 16384 * (4096 + $uSq * (-768 + $uSq * (320 - 175 * $uSq))); + $B = $uSq / 1024 * (256 + $uSq * (-128 + $uSq * (74 - 47 * $uSq))); + + $sigmaS = $distance / ($b * $A); + $sigma = $sigmaS; + $iterations = 0; + + do { + $cos2SigmaM = cos(2 * $sigma1 + $sigma); + $sinSigma = sin($sigma); + $cosSigma = cos($sigma); + $deltaSigma = $B * $sinSigma + * ($cos2SigmaM + $B / 4 + * ($cosSigma + * (-1 + 2 * $cos2SigmaM * $cos2SigmaM) - $B / 6 + * $cos2SigmaM * (-3 + 4 * $sinSigma * $sinSigma) + * (-3 + 4 * $cos2SigmaM * $cos2SigmaM) + ) + ); + $sigmaS = $sigma; + $sigma = $distance / ($b * $A) + $deltaSigma; + $iterations++; + } while (abs($sigma - $sigmaS) > 1e-12 && $iterations < 200); + + if ($iterations >= 200) { + throw new NotConvergingException('Inverse Vincenty Formula did not converge'); + } + + $tmp = $sinU1 * $sinSigma - $cosU1 * $cosSigma * $cosAlpha1; + $phi2 = atan2( + $sinU1 * $cosSigma + $cosU1 * $sinSigma * $cosAlpha1, + (1 - $f) * sqrt($sinAlpha * $sinAlpha + $tmp * $tmp) + ); + $lambda = atan2($sinSigma * $sinAlpha1, $cosU1 * $cosSigma - $sinU1 * $sinSigma * $cosAlpha1); + $C = $f / 16 * $cosSquAlpha * (4 + $f * (4 - 3 * $cosSquAlpha)); + $L = $lambda + - (1 - $C) * $f * $sinAlpha + * ($sigma + $C * $sinSigma * ($cos2SigmaM + $C * $cosSigma * (-1 + 2 * $cos2SigmaM ** 2))); + $lambda2 = fmod($lambda1 + $L + 3 * M_PI, 2 * M_PI) - M_PI; + + $alpha2 = atan2($sinAlpha, -$tmp); + $alpha2 = fmod($alpha2 + 2 * M_PI, 2 * M_PI); + + return new DirectVincentyBearing( + new Coordinate(rad2deg($phi2), rad2deg($lambda2), $point->getEllipsoid()), + rad2deg($alpha2) + ); + } + + /** + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return InverseVincentyBearing + * + * @throws NotConvergingException + */ + private function inverseVincenty(Coordinate $point1, Coordinate $point2): InverseVincentyBearing + { + $φ1 = deg2rad($point1->getLat()); + $φ2 = deg2rad($point2->getLat()); + $λ1 = deg2rad($point1->getLng()); + $λ2 = deg2rad($point2->getLng()); + + $a = $point1->getEllipsoid()->getA(); + $b = $point1->getEllipsoid()->getB(); + $f = 1 / $point1->getEllipsoid()->getF(); + + $L = $λ2 - $λ1; + + $tanU1 = (1 - $f) * tan($φ1); + $cosU1 = 1 / sqrt(1 + $tanU1 * $tanU1); + $sinU1 = $tanU1 * $cosU1; + $tanU2 = (1 - $f) * tan($φ2); + $cosU2 = 1 / sqrt(1 + $tanU2 * $tanU2); + $sinU2 = $tanU2 * $cosU2; + + $λ = $L; + + $iterations = 0; + + do { + $sinλ = sin($λ); + $cosλ = cos($λ); + $sinSqσ = ($cosU2 * $sinλ) * ($cosU2 * $sinλ) + + ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ) * ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ); + $sinσ = sqrt($sinSqσ); + + if ($sinσ == 0) { + new InverseVincentyBearing(0, 0, 0); + } + + $cosσ = $sinU1 * $sinU2 + $cosU1 * $cosU2 * $cosλ; + $σ = atan2($sinσ, $cosσ); + $sinα = $cosU1 * $cosU2 * $sinλ / $sinσ; + $cosSqα = 1 - $sinα * $sinα; + + $cos2σM = 0; + if ($cosSqα !== 0.0) { + $cos2σM = $cosσ - 2 * $sinU1 * $sinU2 / $cosSqα; + } + + $C = $f / 16 * $cosSqα * (4 + $f * (4 - 3 * $cosSqα)); + $λp = $λ; + $λ = $L + (1 - $C) * $f * $sinα + * ($σ + $C * $sinσ * ($cos2σM + $C * $cosσ * (-1 + 2 * $cos2σM * $cos2σM))); + $iterations++; + } while (abs($λ - $λp) > 1e-12 && $iterations < 200); + + if ($iterations >= 200) { + throw new NotConvergingException('Inverse Vincenty Formula did not converge'); + } + + $uSq = $cosSqα * ($a * $a - $b * $b) / ($b * $b); + $A = 1 + $uSq / 16384 * (4096 + $uSq * (-768 + $uSq * (320 - 175 * $uSq))); + $B = $uSq / 1024 * (256 + $uSq * (-128 + $uSq * (74 - 47 * $uSq))); + $Δσ = $B * $sinσ + * ($cos2σM + $B / 4 + * ($cosσ * (-1 + 2 * $cos2σM * $cos2σM) - $B / 6 + * $cos2σM * (-3 + 4 * $sinσ * $sinσ) + * (-3 + 4 * $cos2σM * $cos2σM) + ) + ); + + $s = $b * $A * ($σ - $Δσ); + + $α1 = atan2($cosU2 * $sinλ, $cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosλ); + $α2 = atan2($cosU1 * $sinλ, -$sinU1 * $cosU2 + $cosU1 * $sinU2 * $cosλ); + + $α1 = fmod($α1 + 2 * M_PI, 2 * M_PI); + $α2 = fmod($α2 + 2 * M_PI, 2 * M_PI); + + $s = round($s, 3); + + return new InverseVincentyBearing($s, rad2deg($α1), rad2deg($α2)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingInterface.php b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingInterface.php new file mode 100644 index 000000000..2557af158 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingInterface.php @@ -0,0 +1,48 @@ + + */ +interface BearingInterface +{ + /** + * This method calculates the initial bearing between the + * two points. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float Bearing Angle + */ + public function calculateBearing(Coordinate $point1, Coordinate $point2): float; + + /** + * Calculates the final bearing between the two points. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float + */ + public function calculateFinalBearing(Coordinate $point1, Coordinate $point2): float; + + /** + * Calculates a destination point for the given point, bearing angle, + * and distance. + * + * @param Coordinate $point + * @param float $bearing the bearing angle between 0 and 360 degrees + * @param float $distance the distance to the destination point in meters + * + * @return Coordinate + */ + public function calculateDestination(Coordinate $point, float $bearing, float $distance): Coordinate; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingSpherical.php b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingSpherical.php new file mode 100644 index 000000000..d2cd34f91 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bearing/BearingSpherical.php @@ -0,0 +1,89 @@ + + */ +class BearingSpherical implements BearingInterface +{ + /** + * Earth radius in meters. + */ + private const EARTH_RADIUS = 6371009.0; + + /** + * This method calculates the initial bearing (forward azimut) between + * the two given points. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float Bearing Angle in degrees + */ + public function calculateBearing(Coordinate $point1, Coordinate $point2): float + { + $lat1 = deg2rad($point1->getLat()); + $lat2 = deg2rad($point2->getLat()); + $lng1 = deg2rad($point1->getLng()); + $lng2 = deg2rad($point2->getLng()); + + $y = sin($lng2 - $lng1) * cos($lat2); + $x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($lng2 - $lng1); + + $bearing = rad2deg(atan2($y, $x)); + + if ($bearing < 0) { + $bearing = fmod($bearing + 360, 360); + } + + return $bearing; + } + + /** + * Calculates the final bearing between the two points. + * + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float + */ + public function calculateFinalBearing(Coordinate $point1, Coordinate $point2): float + { + $initialBearing = $this->calculateBearing($point2, $point1); + + return fmod($initialBearing + 180, 360); + } + + /** + * Calculates a destination point for the given point, bearing angle, + * and distance. + * + * @param Coordinate $point + * @param float $bearing the bearing angle between 0 and 360 degrees + * @param float $distance the distance to the destination point in meters + * + * @return Coordinate + * @throws InvalidArgumentException + */ + public function calculateDestination(Coordinate $point, float $bearing, float $distance): Coordinate + { + $D = $distance / self::EARTH_RADIUS; + $B = deg2rad($bearing); + $φ = deg2rad($point->getLat()); + $λ = deg2rad($point->getLng()); + + $Φ = asin(sin($φ) * cos($D) + cos($φ) * sin($D) * cos($B)); + $Λ = $λ + atan2(sin($B) * sin($D) * cos($φ), cos($D) - sin($φ) * sin($φ)); + + return new Coordinate(rad2deg($Φ), rad2deg($Λ)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Bearing/DirectVincentyBearing.php b/admin/vendor/mjaschen/phpgeo/src/Bearing/DirectVincentyBearing.php new file mode 100644 index 000000000..19964383b --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bearing/DirectVincentyBearing.php @@ -0,0 +1,53 @@ + + */ +class DirectVincentyBearing +{ + /** + * @var Coordinate + */ + private $destination; + + /** + * @var float + */ + private $bearingFinal; + + /** + * Bearing constructor. + * + * @param Coordinate $destination + * @param float $bearingFinal + */ + public function __construct(Coordinate $destination, float $bearingFinal) + { + $this->destination = $destination; + $this->bearingFinal = $bearingFinal; + } + + /** + * @return Coordinate + */ + public function getDestination(): Coordinate + { + return $this->destination; + } + + /** + * @return float + */ + public function getBearingFinal(): float + { + return $this->bearingFinal; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Bearing/InverseVincentyBearing.php b/admin/vendor/mjaschen/phpgeo/src/Bearing/InverseVincentyBearing.php new file mode 100644 index 000000000..f918e1ce0 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bearing/InverseVincentyBearing.php @@ -0,0 +1,66 @@ + + */ +class InverseVincentyBearing +{ + /** + * @var float + */ + private $distance; + + /** + * @var float + */ + private $bearingInitial; + + /** + * @var float + */ + private $bearingFinal; + + /** + * InverseVincentyBearing constructor. + * + * @param float $distance + * @param float $bearingInitial + * @param float $bearingFinal + */ + public function __construct(float $distance, float $bearingInitial, float $bearingFinal) + { + $this->distance = $distance; + $this->bearingInitial = $bearingInitial; + $this->bearingFinal = $bearingFinal; + } + + /** + * @return float + */ + public function getDistance(): float + { + return $this->distance; + } + + /** + * @return float + */ + public function getBearingInitial(): float + { + return $this->bearingInitial; + } + + /** + * @return float + */ + public function getBearingFinal(): float + { + return $this->bearingFinal; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Bounds.php b/admin/vendor/mjaschen/phpgeo/src/Bounds.php new file mode 100644 index 000000000..261fdf44f --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Bounds.php @@ -0,0 +1,118 @@ +northWest = $northWest; + $this->southEast = $southEast; + } + + public function getNorthWest(): Coordinate + { + return $this->northWest; + } + + public function getSouthEast(): Coordinate + { + return $this->southEast; + } + + public function getNorthEast(): Coordinate + { + return new Coordinate($this->getNorth(), $this->getEast()); + } + + public function getSouthWest(): Coordinate + { + return new Coordinate($this->getSouth(), $this->getWest()); + } + + public function getNorth(): float + { + return $this->northWest->getLat(); + } + + public function getSouth(): float + { + return $this->southEast->getLat(); + } + + public function getWest(): float + { + return $this->northWest->getLng(); + } + + public function getEast(): float + { + return $this->southEast->getLng(); + } + + /** + * Calculates the center of this bounds object and returns it as a + * Coordinate instance. + * + * @throws \InvalidArgumentException + */ + public function getCenter(): Coordinate + { + $centerLat = ($this->getNorth() + $this->getSouth()) / 2; + + return new Coordinate($centerLat, $this->getCenterLng()); + } + + protected function getCenterLng(): float + { + $centerLng = ($this->getEast() + $this->getWest()) / 2; + + $overlap = $this->getWest() > 0 && $this->getEast() < 0; + + if ($overlap && $centerLng > 0) { + return -180.0 + $centerLng; + } + + if ($overlap && $centerLng < 0) { + return 180.0 + $centerLng; + } + + if ($overlap && $centerLng == 0) { + return 180.0; + } + + return $centerLng; + } + + /** + * Creates the polygon described by this bounds object and returns the + * Polygon instance. + */ + public function getAsPolygon(): Polygon + { + $polygon = new Polygon(); + + $polygon->addPoint($this->getNorthWest()); + $polygon->addPoint($this->getNorthEast()); + $polygon->addPoint($this->getSouthEast()); + $polygon->addPoint($this->getSouthWest()); + + return $polygon; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirection.php b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirection.php new file mode 100644 index 000000000..e89e1b9cc --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirection.php @@ -0,0 +1,133 @@ +direction = new Direction(); + } + + public function getCardinalDirection(Coordinate $point1, Coordinate $point2): string + { + $directionFunctionMapping = [ + self::CARDINAL_DIRECTION_NORTH => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isStrictlyNorth($point1, $point2); + }, + self::CARDINAL_DIRECTION_EAST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isStrictlyEast($point1, $point2); + }, + self::CARDINAL_DIRECTION_SOUTH => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isStrictlySouth($point1, $point2); + }, + self::CARDINAL_DIRECTION_WEST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isStrictlyWest($point1, $point2); + }, + self::CARDINAL_DIRECTION_NORTHEAST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isNorthEast($point1, $point2); + }, + self::CARDINAL_DIRECTION_SOUTHEAST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isSouthEast($point1, $point2); + }, + self::CARDINAL_DIRECTION_SOUTHWEST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isSouthWest($point1, $point2); + }, + self::CARDINAL_DIRECTION_NORTHWEST => function (Coordinate $point1, Coordinate $point2): bool { + return $this->isNorthWest($point1, $point2); + }, + ]; + + foreach ($directionFunctionMapping as $direction => $checkFunction) { + if ($checkFunction($point1, $point2)) { + return $direction; + } + } + + return self::CARDINAL_DIRECTION_NONE; + } + + private function isStrictlyNorth(Coordinate $point1, Coordinate $point2): bool + { + return !$this->direction->pointIsEastOf($point1, $point2) + && !$this->direction->pointIsSouthOf($point1, $point2) + && !$this->direction->pointIsWestOf($point1, $point2) + && $this->direction->pointIsNorthOf($point1, $point2); + } + + private function isStrictlyEast(Coordinate $point1, Coordinate $point2): bool + { + return $this->direction->pointIsEastOf($point1, $point2) + && !$this->direction->pointIsSouthOf($point1, $point2) + && !$this->direction->pointIsWestOf($point1, $point2) + && !$this->direction->pointIsNorthOf($point1, $point2); + } + + private function isStrictlySouth(Coordinate $point1, Coordinate $point2): bool + { + return !$this->direction->pointIsEastOf($point1, $point2) + && $this->direction->pointIsSouthOf($point1, $point2) + && !$this->direction->pointIsWestOf($point1, $point2) + && !$this->direction->pointIsNorthOf($point1, $point2); + } + + private function isStrictlyWest(Coordinate $point1, Coordinate $point2): bool + { + return !$this->direction->pointIsEastOf($point1, $point2) + && !$this->direction->pointIsSouthOf($point1, $point2) + && $this->direction->pointIsWestOf($point1, $point2) + && !$this->direction->pointIsNorthOf($point1, $point2); + } + + private function isNorthEast(Coordinate $point1, Coordinate $point2): bool + { + return $this->direction->pointIsEastOf($point1, $point2) + && !$this->direction->pointIsSouthOf($point1, $point2) + && !$this->direction->pointIsWestOf($point1, $point2) + && $this->direction->pointIsNorthOf($point1, $point2); + } + + private function isSouthEast(Coordinate $point1, Coordinate $point2): bool + { + return $this->direction->pointIsEastOf($point1, $point2) + && $this->direction->pointIsSouthOf($point1, $point2) + && !$this->direction->pointIsWestOf($point1, $point2) + && !$this->direction->pointIsNorthOf($point1, $point2); + } + + private function isSouthWest(Coordinate $point1, Coordinate $point2): bool + { + return !$this->direction->pointIsEastOf($point1, $point2) + && $this->direction->pointIsSouthOf($point1, $point2) + && $this->direction->pointIsWestOf($point1, $point2) + && !$this->direction->pointIsNorthOf($point1, $point2); + } + + private function isNorthWest(Coordinate $point1, Coordinate $point2): bool + { + return !$this->direction->pointIsEastOf($point1, $point2) + && !$this->direction->pointIsSouthOf($point1, $point2) + && $this->direction->pointIsWestOf($point1, $point2) + && $this->direction->pointIsNorthOf($point1, $point2); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistances.php b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistances.php new file mode 100644 index 000000000..2252870f0 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistances.php @@ -0,0 +1,133 @@ +north = $north; + $this->east = $east; + $this->south = $south; + $this->west = $west; + } + + /** + * @psalm-pure + * @psalm-mutation-free + */ + public static function create(): self + { + return new self(0, 0, 0, 0); + } + + /** + * @psalm-mutation-free + */ + public function setNorth(float $north): self + { + $this->assertPositiveFloat($north); + + return new self($north, $this->east, $this->south, $this->west); + } + + /** + * @psalm-mutation-free + */ + public function setEast(float $east): self + { + $this->assertPositiveFloat($east); + + return new self($this->north, $east, $this->south, $this->west); + } + + /** + * @psalm-mutation-free + */ + public function setSouth(float $south): self + { + $this->assertPositiveFloat($south); + + return new self($this->north, $this->east, $south, $this->west); + } + + /** + * @psalm-mutation-free + */ + public function setWest(float $west): self + { + $this->assertPositiveFloat($west); + + return new self($this->north, $this->east, $this->south, $west); + } + + /** + * @psalm-mutation-free + */ + public function getNorth(): float + { + return $this->north; + } + + /** + * @psalm-mutation-free + */ + public function getEast(): float + { + return $this->east; + } + + /** + * @psalm-mutation-free + */ + public function getSouth(): float + { + return $this->south; + } + + /** + * @psalm-mutation-free + */ + public function getWest(): float + { + return $this->west; + } + + /** + * @psalm-pure + * @psalm-mutation-free + * + * @throws InvalidDistanceException + */ + private function assertPositiveFloat(float $value): void + { + if ($value < 0) { + throw new InvalidDistanceException('Negative distance is invalid.', 1857757416); + } + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistancesCalculator.php b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistancesCalculator.php new file mode 100644 index 000000000..0c7fb9492 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/CardinalDirection/CardinalDirectionDistancesCalculator.php @@ -0,0 +1,78 @@ +getCardinalDirection($point1, $point2); + $directDistance = $point1->getDistance($point2, $distanceCalculator); + + switch ($cardinalDirection) { + case CardinalDirection::CARDINAL_DIRECTION_NONE: + return CardinalDirectionDistances::create(); + + case CardinalDirection::CARDINAL_DIRECTION_NORTH: + return CardinalDirectionDistances::create()->setSouth($directDistance); + + case CardinalDirection::CARDINAL_DIRECTION_EAST: + return CardinalDirectionDistances::create()->setWest($directDistance); + + case CardinalDirection::CARDINAL_DIRECTION_SOUTH: + return CardinalDirectionDistances::create()->setNorth($directDistance); + + case CardinalDirection::CARDINAL_DIRECTION_WEST: + return CardinalDirectionDistances::create()->setEast($directDistance); + + case CardinalDirection::CARDINAL_DIRECTION_NORTHWEST: + $bounds = new Bounds($point1, $point2); + $point3 = new Coordinate($bounds->getNorth(), $bounds->getEast()); + + return CardinalDirectionDistances::create() + ->setEast($point1->getDistance($point3, $distanceCalculator)) + ->setSouth($point3->getDistance($point2, $distanceCalculator)); + + case CardinalDirection::CARDINAL_DIRECTION_SOUTHWEST: + $bounds = new Bounds( + new Coordinate($point2->getLat(), $point1->getLng()), + new Coordinate($point1->getLat(), $point2->getLng()) + ); + $point3 = new Coordinate($bounds->getSouth(), $bounds->getEast()); + + return CardinalDirectionDistances::create() + ->setNorth($point3->getDistance($point2, $distanceCalculator)) + ->setEast($point1->getDistance($point3, $distanceCalculator)); + + case CardinalDirection::CARDINAL_DIRECTION_NORTHEAST: + $bounds = new Bounds( + new Coordinate($point1->getLat(), $point2->getLng()), + new Coordinate($point2->getLat(), $point1->getLng()) + ); + $point3 = new Coordinate($bounds->getNorth(), $bounds->getWest()); + + return CardinalDirectionDistances::create() + ->setSouth($point3->getDistance($point2, $distanceCalculator)) + ->setWest($point1->getDistance($point3, $distanceCalculator)); + + case CardinalDirection::CARDINAL_DIRECTION_SOUTHEAST: + $bounds = new Bounds($point2, $point1); + $point3 = new Coordinate($bounds->getSouth(), $bounds->getWest()); + + return CardinalDirectionDistances::create() + ->setNorth($point3->getDistance($point2, $distanceCalculator)) + ->setWest($point1->getDistance($point3, $distanceCalculator)); + } + + return CardinalDirectionDistances::create(); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Coordinate.php b/admin/vendor/mjaschen/phpgeo/src/Coordinate.php new file mode 100644 index 000000000..49283b508 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Coordinate.php @@ -0,0 +1,176 @@ + + */ +class Coordinate implements GeometryInterface +{ + /** + * @var float + */ + protected $lat; + + /** + * @var float + */ + protected $lng; + + /** + * @var Ellipsoid + */ + protected $ellipsoid; + + /** + * @param float $lat -90.0 .. +90.0 + * @param float $lng -180.0 .. +180.0 + * @param ?Ellipsoid $ellipsoid if omitted, WGS-84 is used + * + * @throws InvalidArgumentException + */ + public function __construct(float $lat, float $lng, ?Ellipsoid $ellipsoid = null) + { + if (! $this->isValidLatitude($lat)) { + throw new InvalidArgumentException('Latitude value must be numeric -90.0 .. +90.0 (given: ' . $lat . ')'); + } + + if (! $this->isValidLongitude($lng)) { + throw new InvalidArgumentException( + 'Longitude value must be numeric -180.0 .. +180.0 (given: ' . $lng . ')' + ); + } + + $this->lat = $lat; + $this->lng = $lng; + + if ($ellipsoid instanceof Ellipsoid) { + $this->ellipsoid = $ellipsoid; + + return; + } + + $this->ellipsoid = Ellipsoid::createDefault(); + } + + public function getLat(): float + { + return $this->lat; + } + + public function getLng(): float + { + return $this->lng; + } + + /** + * @return array + */ + public function getPoints(): array + { + return [$this]; + } + + public function getEllipsoid(): Ellipsoid + { + return $this->ellipsoid; + } + + /** + * Calculates the distance between the given coordinate + * and this coordinate. + */ + public function getDistance(Coordinate $coordinate, DistanceInterface $calculator): float + { + return $calculator->getDistance($this, $coordinate); + } + + /** + * Calculates the cardinal direction distances from this coordinate + * to given coordinate. + */ + public function getCardinalDirectionDistances( + Coordinate $coordinate, + DistanceInterface $calculator + ): CardinalDirectionDistances { + return (new CardinalDirectionDistancesCalculator()) + ->getCardinalDirectionDistances($this, $coordinate, $calculator); + } + + /** + * Checks if two points describe the same location within an allowed distance. + * + * Uses the Haversine distance calculator for distance calculation as it's + * precise enough for short-distance calculations. + * + * @see Haversine + */ + public function hasSameLocation(Coordinate $coordinate, float $allowedDistance = .001): bool + { + return $this->getDistance($coordinate, new Haversine()) <= $allowedDistance; + } + + /** + * Checks if this point intersects a given geometry. + * + * @throws InvalidGeometryException + */ + public function intersects(GeometryInterface $geometry): bool + { + if ($geometry instanceof self) { + return $this->hasSameLocation($geometry); + } + + if ($geometry instanceof Polygon) { + return $geometry->contains($this); + } + + throw new InvalidGeometryException('Only polygons can contain other geometries', 1655191821); + } + + public function format(FormatterInterface $formatter): string + { + return $formatter->format($this); + } + + protected function isValidLatitude(float $latitude): bool + { + return $this->isNumericInBounds($latitude, -90.0, 90.0); + } + + protected function isValidLongitude(float $longitude): bool + { + return $this->isNumericInBounds($longitude, -180.0, 180.0); + } + + /** + * Checks if the given value is (1) numeric, and (2) between lower + * and upper bounds (including the bounds values). + */ + protected function isNumericInBounds(float $value, float $lower, float $upper): bool + { + return !($value < $lower || $value > $upper); + } + + public function getBounds(): Bounds + { + return new Bounds($this, $this); + } + + public function getSegments(): array + { + throw new \RuntimeException('A single point instance does not contain valid segments', 6029644914); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Direction/Direction.php b/admin/vendor/mjaschen/phpgeo/src/Direction/Direction.php new file mode 100644 index 000000000..00bb7a013 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Direction/Direction.php @@ -0,0 +1,30 @@ +getLat() > $compareAgainst->getLat(); + } + + public function pointIsSouthOf(Coordinate $point, Coordinate $compareAgainst): bool + { + return $point->getLat() < $compareAgainst->getLat(); + } + + public function pointIsEastOf(Coordinate $point, Coordinate $compareAgainst): bool + { + return $point->getLng() > $compareAgainst->getLng(); + } + + public function pointIsWestOf(Coordinate $point, Coordinate $compareAgainst): bool + { + return $point->getLng() < $compareAgainst->getLng(); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Distance/DistanceInterface.php b/admin/vendor/mjaschen/phpgeo/src/Distance/DistanceInterface.php new file mode 100644 index 000000000..4f7683959 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Distance/DistanceInterface.php @@ -0,0 +1,23 @@ + + */ +interface DistanceInterface +{ + /** + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @return float distance between the two coordinates in meters + */ + public function getDistance(Coordinate $point1, Coordinate $point2): float; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Distance/Haversine.php b/admin/vendor/mjaschen/phpgeo/src/Distance/Haversine.php new file mode 100644 index 000000000..b143fc8c7 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Distance/Haversine.php @@ -0,0 +1,53 @@ + + */ +class Haversine implements DistanceInterface +{ + /** + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @throws NotMatchingEllipsoidException + * + * @return float + */ + public function getDistance(Coordinate $point1, Coordinate $point2): float + { + if ($point1->getEllipsoid()->getName() !== $point2->getEllipsoid()->getName()) { + throw new NotMatchingEllipsoidException('The ellipsoids for both coordinates must match'); + } + + $lat1 = deg2rad($point1->getLat()); + $lat2 = deg2rad($point2->getLat()); + $lng1 = deg2rad($point1->getLng()); + $lng2 = deg2rad($point2->getLng()); + + $dLat = $lat2 - $lat1; + $dLng = $lng2 - $lng1; + + $radius = $point1->getEllipsoid()->getArithmeticMeanRadius(); + + $distance = 2 * $radius * asin( + sqrt( + (sin($dLat / 2) ** 2) + + cos($lat1) * cos($lat2) * (sin($dLng / 2) ** 2) + ) + ); + + return round($distance, 3); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Distance/Vincenty.php b/admin/vendor/mjaschen/phpgeo/src/Distance/Vincenty.php new file mode 100644 index 000000000..4e2d480c1 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Distance/Vincenty.php @@ -0,0 +1,111 @@ + + */ +class Vincenty implements DistanceInterface +{ + /** + * @param Coordinate $point1 + * @param Coordinate $point2 + * + * @throws NotMatchingEllipsoidException + * @throws NotConvergingException + * + * @return float + */ + public function getDistance(Coordinate $point1, Coordinate $point2): float + { + if ($point1->getEllipsoid()->getName() !== $point2->getEllipsoid()->getName()) { + throw new NotMatchingEllipsoidException('The ellipsoids for both coordinates must match'); + } + + $lat1 = deg2rad($point1->getLat()); + $lat2 = deg2rad($point2->getLat()); + $lng1 = deg2rad($point1->getLng()); + $lng2 = deg2rad($point2->getLng()); + + $a = $point1->getEllipsoid()->getA(); + $b = $point1->getEllipsoid()->getB(); + $f = 1 / $point1->getEllipsoid()->getF(); + + $L = $lng2 - $lng1; + $U1 = atan((1 - $f) * tan($lat1)); + $U2 = atan((1 - $f) * tan($lat2)); + + $iterationsLeft = 100; + $lambda = $L; + + $sinU1 = sin($U1); + $sinU2 = sin($U2); + $cosU1 = cos($U1); + $cosU2 = cos($U2); + + do { + $sinLambda = sin($lambda); + $cosLambda = cos($lambda); + + $sinSigma = sqrt( + $cosU2 * $sinLambda * $cosU2 * $sinLambda + + ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda) * ($cosU1 * $sinU2 - $sinU1 * $cosU2 * $cosLambda) + ); + + if (abs($sinSigma) < 1E-12) { + return 0.0; + } + + $cosSigma = $sinU1 * $sinU2 + $cosU1 * $cosU2 * $cosLambda; + + $sigma = atan2($sinSigma, $cosSigma); + + $sinAlpha = $cosU1 * $cosU2 * $sinLambda / $sinSigma; + + $cosSqAlpha = 1 - $sinAlpha * $sinAlpha; + + $cos2SigmaM = 0; + if (abs($cosSqAlpha) > 1E-12) { + $cos2SigmaM = $cosSigma - 2 * $sinU1 * $sinU2 / $cosSqAlpha; + } + + $C = $f / 16 * $cosSqAlpha * (4 + $f * (4 - 3 * $cosSqAlpha)); + + $lambdaP = $lambda; + + $lambda = $L + + (1 - $C) + * $f + * $sinAlpha + * ($sigma + $C * $sinSigma * ($cos2SigmaM + $C * $cosSigma * (- 1 + 2 * $cos2SigmaM * $cos2SigmaM))); + + $iterationsLeft--; + } while (abs($lambda - $lambdaP) > 1e-12 && $iterationsLeft > 0); + + if ($iterationsLeft === 0) { + throw new NotConvergingException('Vincenty calculation does not converge'); + } + + $uSq = $cosSqAlpha * ($a * $a - $b * $b) / ($b * $b); + $A = 1 + $uSq / 16384 * (4096 + $uSq * (- 768 + $uSq * (320 - 175 * $uSq))); + $B = $uSq / 1024 * (256 + $uSq * (- 128 + $uSq * (74 - 47 * $uSq))); + $deltaSigma = $B * $sinSigma * ( + $cos2SigmaM + + $B / 4 * ($cosSigma * (- 1 + 2 * $cos2SigmaM * $cos2SigmaM) + - $B / 6 * $cos2SigmaM * (- 3 + 4 * $sinSigma * $sinSigma) * (- 3 + 4 * $cos2SigmaM * $cos2SigmaM)) + ); + $s = $b * $A * ($sigma - $deltaSigma); + + return round($s, 3); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Ellipsoid.php b/admin/vendor/mjaschen/phpgeo/src/Ellipsoid.php new file mode 100644 index 000000000..307646ce4 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Ellipsoid.php @@ -0,0 +1,128 @@ + + */ +class Ellipsoid +{ + /** + * @var string + */ + protected $name; + + /** + * The semi-major axis + * + * @var float + */ + protected $a; + + /** + * The Inverse Flattening (1/f) + * + * @var float + */ + protected $f; + + /** + * Some often used ellipsoids + * + * @var array + */ + protected static $configs = [ + 'WGS-84' => [ + 'name' => 'World Geodetic System 1984', + 'a' => 6378137.0, + 'f' => 298.257223563, + ], + 'GRS-80' => [ + 'name' => 'Geodetic Reference System 1980', + 'a' => 6378137.0, + 'f' => 298.257222100, + ], + ]; + + /** + * @param string $name + * @param float $a + * @param float $f + */ + public function __construct(string $name, float $a, float $f) + { + $this->name = $name; + $this->a = $a; + $this->f = $f; + } + + /** + * @param string $name + * + * @return Ellipsoid + */ + public static function createDefault(string $name = 'WGS-84'): Ellipsoid + { + return static::createFromArray(static::$configs[$name]); + } + + /** + * @param array $config + * + * @return Ellipsoid + */ + public static function createFromArray(array $config): Ellipsoid + { + return new self($config['name'], $config['a'], $config['f']); + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return float + */ + public function getA(): float + { + return $this->a; + } + + /** + * Calculation of the semi-minor axis + * + * @return float + */ + public function getB(): float + { + return $this->a * (1 - 1 / $this->f); + } + + /** + * @return float + */ + public function getF(): float + { + return $this->f; + } + + /** + * Calculates the arithmetic mean radius + * + * @see http://home.online.no/~sigurdhu/WGS84_Eng.html + * + * @return float + */ + public function getArithmeticMeanRadius(): float + { + return $this->a * (1 - 1 / $this->f / 3); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Exception/BearingNotAvailableException.php b/admin/vendor/mjaschen/phpgeo/src/Exception/BearingNotAvailableException.php new file mode 100644 index 000000000..40f431b67 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Exception/BearingNotAvailableException.php @@ -0,0 +1,9 @@ +calculateDestination($center, 315, $distance); + $southEast = $bearing->calculateDestination($center, 135, $distance); + + return new Bounds($northWest, $southEast); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Factory/CoordinateFactory.php b/admin/vendor/mjaschen/phpgeo/src/Factory/CoordinateFactory.php new file mode 100644 index 000000000..5f3ca4abe --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Factory/CoordinateFactory.php @@ -0,0 +1,163 @@ + + */ +class CoordinateFactory implements GeometryFactoryInterface +{ + /** + * Creates a Coordinate instance from the given string. + * + * The string is parsed by a regular expression for a known + * format of geographical coordinates. + * + * @param string $string formatted geographical coordinate + * + * @throws InvalidArgumentException + */ + public static function fromString(string $string, ?Ellipsoid $ellipsoid = null): Coordinate + { + $string = self::mergeSecondsToMinutes($string); + + $result = self::parseDecimalMinutesWithoutCardinalLetters($string, $ellipsoid); + + if ($result instanceof Coordinate) { + return $result; + } + + $result = self::parseDecimalMinutesWithCardinalLetters($string, $ellipsoid); + + if ($result instanceof Coordinate) { + return $result; + } + + $result = self::parseDecimalDegreesWithoutCardinalLetters($string, $ellipsoid); + + if ($result instanceof Coordinate) { + return $result; + } + + $result = self::parseDecimalDegreesWithCardinalLetters($string, $ellipsoid); + + if ($result instanceof Coordinate) { + return $result; + } + + throw new InvalidArgumentException('Format of coordinates was not recognized'); + } + + /** + * @return Coordinate|null + * @throws InvalidArgumentException + */ + private static function parseDecimalMinutesWithoutCardinalLetters(string $string, ?Ellipsoid $ellipsoid = null) + { + // Decimal minutes without cardinal letters, e. g. "52 12.345, 13 23.456", + // "52° 12.345, 13° 23.456", "52° 12.345′, 13° 23.456′", "52 12.345 N, 13 23.456 E", + // "N52° 12.345′ E13° 23.456′" + $regexp = '/(-?\d{1,2})°?\s+(\d{1,2}\.?\d*)[\'′]?[, ]\s*(-?\d{1,3})°?\s+(\d{1,2}\.?\d*)[\'′]?/u'; + + if (preg_match($regexp, $string, $match) === 1) { + $latitude = (int)$match[1] >= 0 + ? (int)$match[1] + (float)$match[2] / 60 + : (int)$match[1] - (float)$match[2] / 60; + $longitude = (int)$match[3] >= 0 + ? (int)$match[3] + (float)$match[4] / 60 + : (int)$match[3] - (float)$match[4] / 60; + + return new Coordinate($latitude, $longitude, $ellipsoid); + } + + return null; + } + + /** + * @return ?Coordinate + * @throws InvalidArgumentException + */ + private static function parseDecimalMinutesWithCardinalLetters(string $string, ?Ellipsoid $ellipsoid = null) + { + // Decimal minutes with cardinal letters, e. g. "52 12.345, 13 23.456", + // "52° 12.345, 13° 23.456", "52° 12.345′, 13° 23.456′", "52 12.345 N, 13 23.456 E", + // "N52° 12.345′ E13° 23.456′" + $regexp = '/([NS]?\s*)(\d{1,2})°?\s+(\d{1,2}\.?\d*)[\'′]?(\s*[NS]?)'; + $regexp .= '[, ]\s*([EW]?\s*)(\d{1,3})°?\s+(\d{1,2}\.?\d*)[\'′]?(\s*[EW]?)/ui'; + + if (preg_match($regexp, $string, $match) === 1) { + $latitude = (int)$match[2] + (float)$match[3] / 60; + if (strtoupper(trim($match[1])) === 'S' || strtoupper(trim($match[4])) === 'S') { + $latitude = - $latitude; + } + $longitude = (int)$match[6] + (float)$match[7] / 60; + if (strtoupper(trim($match[5])) === 'W' || strtoupper(trim($match[8])) === 'W') { + $longitude = - $longitude; + } + + return new Coordinate($latitude, $longitude, $ellipsoid); + } + + return null; + } + + /** + * @return Coordinate|null + * @throws InvalidArgumentException + */ + private static function parseDecimalDegreesWithoutCardinalLetters(string $string, ?Ellipsoid $ellipsoid = null) + { + // The most simple format: decimal degrees without cardinal letters, + // e. g. "52.5, 13.5" or "53.25732 14.24984" + if (preg_match('/(-?\d{1,2}\.?\d*)°?[, ]\s*(-?\d{1,3}\.?\d*)°?/u', $string, $match) === 1) { + return new Coordinate((float)$match[1], (float)$match[2], $ellipsoid); + } + + return null; + } + + /** + * @return Coordinate|null + * @throws InvalidArgumentException + */ + private static function parseDecimalDegreesWithCardinalLetters(string $string, ?Ellipsoid $ellipsoid = null) + { + // Decimal degrees with cardinal letters, e. g. "N52.5, E13.5", + // "40.2S, 135.3485W", or "56.234°N, 157.245°W" + $regexp = '/([NS]?\s*)(\d{1,2}\.?\d*)°?(\s*[NS]?)[, ]\s*([EW]?\s*)(\d{1,3}\.?\d*)°?(\s*[EW]?)/ui'; + + if (preg_match($regexp, $string, $match) === 1) { + $latitude = $match[2]; + if (strtoupper(trim($match[1])) === 'S' || strtoupper(trim($match[3])) === 'S') { + $latitude = - $latitude; + } + $longitude = $match[5]; + if (strtoupper(trim($match[4])) === 'W' || strtoupper(trim($match[6])) === 'W') { + $longitude = - $longitude; + } + + return new Coordinate((float)$latitude, (float)$longitude, $ellipsoid); + } + + return null; + } + + private static function mergeSecondsToMinutes(string $string): string + { + return preg_replace_callback( + '/(\d+)(°|\s)\s*(\d+)(\'|′|\s)(\s*([0-9\.]*))("|\'\'|″|′′)?/u', + static function (array $matches): string { + return sprintf('%d %f', $matches[1], (float)$matches[3] + (float)$matches[6] / 60); + }, + $string + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Factory/GeometryFactoryInterface.php b/admin/vendor/mjaschen/phpgeo/src/Factory/GeometryFactoryInterface.php new file mode 100644 index 000000000..7858c615b --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Factory/GeometryFactoryInterface.php @@ -0,0 +1,22 @@ + + */ +interface GeometryFactoryInterface +{ + /** + * @param string $string + * + * @return GeometryInterface + */ + public static function fromString(string $string); +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DMS.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DMS.php new file mode 100644 index 000000000..bd1e7aecd --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DMS.php @@ -0,0 +1,216 @@ + + */ +class DMS implements FormatterInterface +{ + public const UNITS_UTF8 = 'UTF-8'; + public const UNITS_ASCII = 'ASCII'; + + /** + * @var string Separator string between latitude and longitude + */ + protected $separator; + + /** + * Use cardinal letters for N/S and W/E instead of minus sign + * + * @var bool + */ + protected $useCardinalLetters; + + /** + * @var string + * + * @psalm-suppress PropertyNotSetInConstructor + */ + protected $unitType; + + /** + * @var array + */ + protected $units = [ + 'UTF-8' => [ + 'deg' => '°', + 'min' => '′', + 'sec' => '″', + ], + 'ASCII' => [ + 'deg' => '°', + 'min' => '\'', + 'sec' => '"', + ], + ]; + + /** + * @throws InvalidArgumentException + */ + public function __construct( + string $separator = ' ', + bool $useCardinalLetters = false, + string $unitType = self::UNITS_UTF8 + ) { + $this->separator = $separator; + $this->useCardinalLetters = $useCardinalLetters; + $this->unitType = $unitType; + } + + /** + * Sets the separator between latitude and longitude values + * + * @param string $separator + * + * @return DMS + * + * @deprecated + */ + public function setSeparator(string $separator): DMS + { + $this->separator = $separator; + + return $this; + } + + /** + * @param bool $value + * + * @return DMS + * + * @deprecated + */ + public function useCardinalLetters(bool $value): DMS + { + $this->useCardinalLetters = $value; + + return $this; + } + + /** + * @param string $type + * + * @return DMS + * @throws InvalidArgumentException + * + * @deprecated + */ + public function setUnits(string $type): DMS + { + if (!array_key_exists($type, $this->units)) { + throw new InvalidArgumentException('Invalid unit type'); + } + + $this->unitType = $type; + + return $this; + } + + /** + * @return string + */ + public function getUnitType(): string + { + return $this->unitType; + } + + /** + * @param Coordinate $coordinate + * + * @return string + */ + public function format(Coordinate $coordinate): string + { + $lat = $coordinate->getLat(); + $lng = $coordinate->getLng(); + + $latValue = abs($lat); + $latDegrees = (int)$latValue; + + $latMinutesDecimal = $latValue - $latDegrees; + $latMinutes = (int)(60 * $latMinutesDecimal); + + $latSeconds = 60 * (60 * $latMinutesDecimal - $latMinutes); + + $lngValue = abs($lng); + $lngDegrees = (int)$lngValue; + + $lngMinutesDecimal = $lngValue - $lngDegrees; + $lngMinutes = (int)(60 * $lngMinutesDecimal); + + $lngSeconds = 60 * (60 * $lngMinutesDecimal - $lngMinutes); + + return sprintf( + '%s%02d%s %02d%s %02d%s%s%s%s%03d%s %02d%s %02d%s%s', + $this->getLatPrefix($lat), + abs($latDegrees), + $this->units[$this->unitType]['deg'], + $latMinutes, + $this->units[$this->unitType]['min'], + round($latSeconds, 0), + $this->units[$this->unitType]['sec'], + $this->getLatSuffix($lat), + $this->separator, + $this->getLngPrefix($lng), + abs($lngDegrees), + $this->units[$this->unitType]['deg'], + $lngMinutes, + $this->units[$this->unitType]['min'], + round($lngSeconds, 0), + $this->units[$this->unitType]['sec'], + $this->getLngSuffix($lng) + ); + } + + protected function getLatPrefix(float $lat): string + { + if ($this->useCardinalLetters || $lat >= 0) { + return ''; + } + + return '-'; + } + + protected function getLngPrefix(float $lng): string + { + if ($this->useCardinalLetters || $lng >= 0) { + return ''; + } + + return '-'; + } + + protected function getLatSuffix(float $lat): string + { + if (!$this->useCardinalLetters) { + return ''; + } + + if ($lat >= 0) { + return ' N'; + } + + return ' S'; + } + + protected function getLngSuffix(float $lng): string + { + if (!$this->useCardinalLetters) { + return ''; + } + + if ($lng >= 0) { + return ' E'; + } + + return ' W'; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalDegrees.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalDegrees.php new file mode 100644 index 000000000..54454ae96 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalDegrees.php @@ -0,0 +1,64 @@ + + */ +class DecimalDegrees implements FormatterInterface +{ + /** + * @var string Separator string between latitude and longitude + */ + protected $separator; + + /** + * @var int + */ + protected $digits = 5; + + /** + * @param string $separator + * @param int $digits + */ + public function __construct(string $separator = ' ', int $digits = 5) + { + $this->separator = $separator; + $this->digits = $digits; + } + + /** + * @param Coordinate $coordinate + * + * @return string + */ + public function format(Coordinate $coordinate): string + { + return sprintf( + '%.' . $this->digits . 'f%s%.' . $this->digits . 'f', + $coordinate->getLat(), + $this->separator, + $coordinate->getLng() + ); + } + + /** + * Sets the separator between latitude and longitude values + * + * @param string $separator + * + * @return $this + */ + public function setSeparator(string $separator): DecimalDegrees + { + $this->separator = $separator; + + return $this; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalMinutes.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalMinutes.php new file mode 100644 index 000000000..2b9da65b8 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/DecimalMinutes.php @@ -0,0 +1,252 @@ + + */ +class DecimalMinutes implements FormatterInterface +{ + public const UNITS_UTF8 = 'UTF-8'; + public const UNITS_ASCII = 'ASCII'; + + /** + * @var string Separator string between latitude and longitude + */ + protected $separator; + + /** + * Use cardinal letters for N/S and W/E instead of minus sign + * + * @var bool + */ + protected $useCardinalLetters; + + /** + * @var string + * + * @psalm-suppress PropertyNotSetInConstructor + */ + protected $unitType; + + /** + * @var int + */ + protected $digits = 3; + + /** + * @var string + */ + protected $decimalPoint = '.'; + + /** + * @var array + */ + protected $units = [ + 'UTF-8' => [ + 'deg' => '°', + 'min' => '′', + ], + 'ASCII' => [ + 'deg' => '°', + 'min' => '\'', + ], + ]; + + /** + * @param string $separator + */ + public function __construct(string $separator = ' ') + { + $this->separator = $separator; + $this->useCardinalLetters = false; + + $this->setUnits(self::UNITS_UTF8); + } + + /** + * Sets the separator between latitude and longitude values + * + * @param string $separator + * + * @return DecimalMinutes + */ + public function setSeparator(string $separator): DecimalMinutes + { + $this->separator = $separator; + + return $this; + } + + /** + * @param bool $value + * + * @return DecimalMinutes + */ + public function useCardinalLetters(bool $value): DecimalMinutes + { + $this->useCardinalLetters = $value; + + return $this; + } + + /** + * @param string $type + * + * @return DecimalMinutes + * @throws \InvalidArgumentException + */ + public function setUnits(string $type): DecimalMinutes + { + if (! array_key_exists($type, $this->units)) { + throw new InvalidArgumentException('Invalid unit type'); + } + + $this->unitType = $type; + + return $this; + } + + /** + * @return string + */ + public function getUnitType(): string + { + return $this->unitType; + } + + /** + * @param int $digits + * + * @return DecimalMinutes + */ + public function setDigits(int $digits): DecimalMinutes + { + $this->digits = $digits; + + return $this; + } + + /** + * @param string $decimalPoint + * + * @return DecimalMinutes + */ + public function setDecimalPoint(string $decimalPoint): DecimalMinutes + { + $this->decimalPoint = $decimalPoint; + + return $this; + } + + /** + * @param Coordinate $coordinate + * + * @return string + */ + public function format(Coordinate $coordinate): string + { + $lat = $coordinate->getLat(); + $lng = $coordinate->getLng(); + + $latValue = abs($lat); + $latDegrees = (int)$latValue; + + $latMinutesDecimal = $latValue - $latDegrees; + $latMinutes = 60 * $latMinutesDecimal; + + $lngValue = abs($lng); + $lngDegrees = (int)$lngValue; + + $lngMinutesDecimal = $lngValue - $lngDegrees; + $lngMinutes = 60 * $lngMinutesDecimal; + + return sprintf( + '%s%02d%s %s%s%s%s%s%03d%s %s%s%s', + $this->getLatPrefix($lat), + abs($latDegrees), + $this->units[$this->unitType]['deg'], + number_format($latMinutes, $this->digits, $this->decimalPoint, $this->decimalPoint), + $this->units[$this->unitType]['min'], + $this->getLatSuffix($lat), + $this->separator, + $this->getLngPrefix($lng), + abs($lngDegrees), + $this->units[$this->unitType]['deg'], + number_format($lngMinutes, $this->digits, $this->decimalPoint, $this->decimalPoint), + $this->units[$this->unitType]['min'], + $this->getLngSuffix($lng) + ); + } + + /** + * @param float $lat + * + * @return string + */ + protected function getLatPrefix(float $lat): string + { + if ($this->useCardinalLetters || $lat >= 0) { + return ''; + } + + return '-'; + } + + /** + * @param float $lng + * + * @return string + */ + protected function getLngPrefix(float $lng): string + { + if ($this->useCardinalLetters || $lng >= 0) { + return ''; + } + + return '-'; + } + + /** + * @param float $lat + * + * @return string + */ + protected function getLatSuffix(float $lat): string + { + if (! $this->useCardinalLetters) { + return ''; + } + + if ($lat >= 0) { + return ' N'; + } + + return ' S'; + } + + /** + * @param float $lng + * + * @return string + */ + protected function getLngSuffix(float $lng): string + { + if (! $this->useCardinalLetters) { + return ''; + } + + if ($lng >= 0) { + return ' E'; + } + + return ' W'; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/FormatterInterface.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/FormatterInterface.php new file mode 100644 index 000000000..fe35c23b4 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/FormatterInterface.php @@ -0,0 +1,22 @@ + + */ +interface FormatterInterface +{ + /** + * @param Coordinate $coordinate + * + * @return string + */ + public function format(Coordinate $coordinate): string; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/GeoJSON.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/GeoJSON.php new file mode 100644 index 000000000..7d831358d --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Coordinate/GeoJSON.php @@ -0,0 +1,33 @@ + + */ +class GeoJSON implements FormatterInterface +{ + /** + * @param Coordinate $coordinate + * + * @return string + */ + public function format(Coordinate $coordinate): string + { + return json_encode( + [ + 'type' => 'Point', + 'coordinates' => [ + $coordinate->getLng(), + $coordinate->getLat(), + ], + ] + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/FormatterInterface.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/FormatterInterface.php new file mode 100644 index 000000000..a20981ea0 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/FormatterInterface.php @@ -0,0 +1,23 @@ + + * @author Richard Barnes + */ +interface FormatterInterface +{ + /** + * @param Polygon $polygon + * + * @return string + */ + public function format(Polygon $polygon): string; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/GeoJSON.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/GeoJSON.php new file mode 100644 index 000000000..bd728f48a --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polygon/GeoJSON.php @@ -0,0 +1,45 @@ + + */ +class GeoJSON implements FormatterInterface +{ + /** + * @param Polygon $polygon + * + * @return string + * + * @throws InvalidPolygonException + */ + public function format(Polygon $polygon): string + { + if ($polygon->getNumberOfPoints() < 3) { + throw new InvalidPolygonException('A polygon must consist of at least three points.'); + } + + $points = []; + + /** @var Coordinate $point */ + foreach ($polygon->getPoints() as $point) { + $points[] = [$point->getLng(), $point->getLat()]; + } + + return json_encode( + [ + 'type' => 'Polygon', + 'coordinates' => [$points], + ] + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/FormatterInterface.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/FormatterInterface.php new file mode 100644 index 000000000..a29bfaae0 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/FormatterInterface.php @@ -0,0 +1,22 @@ + + */ +interface FormatterInterface +{ + /** + * @param Polyline $polyline + * + * @return string + */ + public function format(Polyline $polyline): string; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/GeoJSON.php b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/GeoJSON.php new file mode 100644 index 000000000..bf7a275fa --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Formatter/Polyline/GeoJSON.php @@ -0,0 +1,36 @@ + + */ +class GeoJSON implements FormatterInterface +{ + /** + * @param Polyline $polyline + * + * @return string + */ + public function format(Polyline $polyline): string + { + $points = []; + + foreach ($polyline->getPoints() as $point) { + $points[] = [$point->getLng(), $point->getLat()]; + } + + return json_encode( + [ + 'type' => 'LineString', + 'coordinates' => $points, + ] + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/GeometryInterface.php b/admin/vendor/mjaschen/phpgeo/src/GeometryInterface.php new file mode 100644 index 000000000..310b13ed7 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/GeometryInterface.php @@ -0,0 +1,15 @@ + + */ + public function getPoints(): array; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/GetBoundsTrait.php b/admin/vendor/mjaschen/phpgeo/src/GetBoundsTrait.php new file mode 100644 index 000000000..2d3e257d6 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/GetBoundsTrait.php @@ -0,0 +1,43 @@ + $points + */ +trait GetBoundsTrait +{ + /** + * @return array + */ + abstract public function getPoints(): array; + + /** + * @return Bounds + */ + public function getBounds(): Bounds + { + $latMin = 90.0; + $latMax = -90.0; + $lngMin = 180.0; + $lngMax = -180.0; + + foreach ($this->getPoints() as $point) { + $latMin = min($point->getLat(), $latMin); + $lngMin = min($point->getLng(), $lngMin); + $latMax = max($point->getLat(), $latMax); + $lngMax = max($point->getLng(), $lngMax); + } + + return new Bounds( + new Coordinate($latMax, $lngMin), + new Coordinate($latMin, $lngMax) + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Intersection/Intersection.php b/admin/vendor/mjaschen/phpgeo/src/Intersection/Intersection.php new file mode 100644 index 000000000..66e77263f --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Intersection/Intersection.php @@ -0,0 +1,90 @@ +contains($geometry2); + } + + if ($geometry1 instanceof Coordinate && $geometry2 instanceof Polygon) { + return $geometry2->contains($geometry1); + } + + if ($precise === true) { + return $this->intersectsGeometry($geometry1, $geometry2); + } + + return $this->intersectsBounds($geometry1, $geometry2); + } + + /** + * Checks if this geometry's bounds and the given bounds intersect. + */ + private function intersectsBounds(GeometryInterface $geometry1, GeometryInterface $geometry2): bool + { + $direction = new Direction(); + /** @var Coordinate|Line|Polyline|Polygon $geometry1 */ + $bounds1 = $geometry1->getBounds(); + /** @var Coordinate|Line|Polyline|Polygon $geometry2 */ + $bounds2 = $geometry2->getBounds(); + + return !( + $direction->pointIsEastOf($bounds1->getSouthWest(), $bounds2->getSouthEast()) + || $direction->pointIsSouthOf($bounds1->getNorthWest(), $bounds2->getSouthWest()) + || $direction->pointIsWestOf($bounds1->getSouthEast(), $bounds2->getSouthWest()) + || $direction->pointIsNorthOf($bounds1->getSouthWest(), $bounds2->getNorthWest()) + ); + } + + /** + * Checks if this geometry and the given geometry intersect by checking + * their segments for intersections. + * + * @throws InvalidGeometryException + */ + private function intersectsGeometry(GeometryInterface $geometry1, GeometryInterface $geometry2): bool + { + if ($geometry1 instanceof Coordinate && $geometry2 instanceof Coordinate) { + return $geometry1->hasSameLocation($geometry2); + } + + if ($geometry1 instanceof Coordinate || $geometry2 instanceof Coordinate) { + throw new InvalidGeometryException('Only can check point intersections for polygons', 7311194789); + } + + if (($geometry1 instanceof Polygon) && $geometry1->containsGeometry($geometry2)) { + return true; + } + + if (($geometry2 instanceof Polygon) && $geometry2->containsGeometry($geometry1)) { + return true; + } + + /** @var Line|Polyline|Polygon $geometry1 */ + foreach ($geometry1->getSegments() as $segment) { + /** @var Line|Polyline|Polygon $geometry2 */ + foreach ($geometry2->getSegments() as $otherSegment) { + if ($segment->intersectsLine($otherSegment)) { + return true; + } + } + } + + return false; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Line.php b/admin/vendor/mjaschen/phpgeo/src/Line.php new file mode 100644 index 000000000..e94bd0fa4 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Line.php @@ -0,0 +1,280 @@ + + */ +class Line implements GeometryInterface +{ + use GetBoundsTrait; + + public const ORIENTATION_COLLINEAR = 0; + public const ORIENTATION_CLOCKWISE = 1; + public const ORIENTATION_ANTI_CLOCKWISE = 2; + + /** + * @var Coordinate + */ + protected $point1; + + /** + * @var Coordinate + */ + protected $point2; + + /** + * @param Coordinate $point1 + * @param Coordinate $point2 + */ + public function __construct(Coordinate $point1, Coordinate $point2) + { + $this->point1 = $point1; + $this->point2 = $point2; + } + + /** + * @param Coordinate $point1 + * + * @return void + * + * @deprecated + */ + public function setPoint1(Coordinate $point1) + { + $this->point1 = $point1; + } + + /** + * @return Coordinate + */ + public function getPoint1(): Coordinate + { + return $this->point1; + } + + /** + * @param Coordinate $point2 + * + * @return void + * + * @deprecated + */ + public function setPoint2(Coordinate $point2) + { + $this->point2 = $point2; + } + + /** + * @return Coordinate + */ + public function getPoint2(): Coordinate + { + return $this->point2; + } + + /** + * Returns an array containing the two points. + * + * @return array + */ + public function getPoints(): array + { + return [$this->point1, $this->point2]; + } + + /** + * Returns an array containing the line segment. + * + * @return array + */ + public function getSegments(): array + { + return [$this]; + } + + /** + * Calculates the length of the line (distance between the two + * coordinates). + * + * @param DistanceInterface $calculator instance of distance calculation class + * + * @return float + */ + public function getLength(DistanceInterface $calculator): float + { + return $calculator->getDistance($this->point1, $this->point2); + } + + /** + * @param BearingInterface $bearingCalculator + * + * @return float + */ + public function getBearing(BearingInterface $bearingCalculator): float + { + return $bearingCalculator->calculateBearing($this->point1, $this->point2); + } + + /** + * @param BearingInterface $bearingCalculator + * + * @return float + */ + public function getFinalBearing(BearingInterface $bearingCalculator): float + { + return $bearingCalculator->calculateFinalBearing($this->point1, $this->point2); + } + + /** + * Create a new instance with reversed point order, i. e. reversed direction. + * + * @return Line + */ + public function getReverse(): Line + { + return new self($this->point2, $this->point1); + } + + /** + * Get the midpoint of a Line segment + * + * @see http://www.movable-type.co.uk/scripts/latlong.html#midpoint + * + * @return Coordinate + */ + public function getMidpoint(): Coordinate + { + $lat1 = deg2rad($this->point1->getLat()); + $lng1 = deg2rad($this->point1->getLng()); + $lat2 = deg2rad($this->point2->getLat()); + $lng2 = deg2rad($this->point2->getLng()); + $deltaLng = $lng2 - $lng1; + + $A = new Cartesian(cos($lat1), 0, sin($lat1)); + $B = new Cartesian(cos($lat2) * cos($deltaLng), cos($lat2) * sin($deltaLng), sin($lat2)); + $C = $A->add($B); + + $latMid = atan2($C->getZ(), sqrt($C->getX() ** 2 + $C->getY() ** 2)); + $lngMid = $lng1 + atan2($C->getY(), $C->getX()); + + return new Coordinate(rad2deg($latMid), rad2deg($lngMid)); + } + + /** + * Returns the point which is located on the line at the + * given fraction (starting at point 1). + * + * @see http://www.movable-type.co.uk/scripts/latlong.html#intermediate-point + * @see http://www.edwilliams.org/avform.htm#Intermediate + * + * @param float $fraction 0.0 ... 1.0 (smaller or larger values work too) + * + * @return Coordinate + * + * @throws RuntimeException + */ + public function getIntermediatePoint(float $fraction): Coordinate + { + $lat1 = deg2rad($this->point1->getLat()); + $lng1 = deg2rad($this->point1->getLng()); + $lat2 = deg2rad($this->point2->getLat()); + $lng2 = deg2rad($this->point2->getLng()); + $deltaLat = $lat2 - $lat1; + $deltaLng = $lng2 - $lng1; + + if ($lat1 + $lat2 == 0.0 && abs($lng1 - $lng2) == M_PI) { + throw new RuntimeException( + 'Start and end points are antipodes, route is therefore undefined.', + 5382449689 + ); + } + + $a = sin($deltaLat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($deltaLng / 2) ** 2; + $delta = 2 * atan2(sqrt($a), sqrt(1 - $a)); + + $A = sin((1 - $fraction) * $delta) / sin($delta); + $B = sin($fraction * $delta) / sin($delta); + + $x = $A * cos($lat1) * cos($lng1) + $B * cos($lat2) * cos($lng2); + $y = $A * cos($lat1) * sin($lng1) + $B * cos($lat2) * sin($lng2); + $z = $A * sin($lat1) + $B * sin($lat2); + + $lat = atan2($z, sqrt($x ** 2 + $y ** 2)); + $lng = atan2($y, $x); + + return new Coordinate(rad2deg($lat), rad2deg($lng)); + } + + /** + * Compares the location of a given coordinate to this line returning + * its orientation as: + * + * - 0 if the coordinate is collinear to this line segment + * - 1 if the coordinate's orientation is clockwise to this line segment + * - 2 if the coordinate's orientation is anti-clockwise to this line segment + */ + public function getOrientation(Coordinate $coordinate): int + { + $crossproduct1 = ($this->point2->getLat() - $this->point1->getLat()) + * ($coordinate->getLng() - $this->point2->getLng()); + $crossproduct2 = ($this->point2->getLng() - $this->point1->getLng()) + * ($coordinate->getLat() - $this->point2->getLat()); + $delta = $crossproduct1 - $crossproduct2; + + if ($delta > 0) { + return self::ORIENTATION_CLOCKWISE; + } + + if ($delta < 0) { + return self::ORIENTATION_ANTI_CLOCKWISE; + } + + return self::ORIENTATION_COLLINEAR; + } + + /** + * Two lines intersect if: + * + * 1. the points of the given line are oriented into opposite directions + * 2. the points of this line are oriented into opposite directions + * 3. the points are collinear and the two line segments are overlapping + */ + public function intersectsLine(Line $line): bool + { + $orientation = []; + $orientation[11] = $this->getOrientation($line->getPoint1()); + $orientation[12] = $this->getOrientation($line->getPoint2()); + $orientation[21] = $line->getOrientation($this->getPoint1()); + $orientation[22] = $line->getOrientation($this->getPoint2()); + + // the lines cross + if ( + $orientation[11] !== $orientation[12] + && $orientation[21] !== $orientation[22] + ) { + return true; + } + + // the lines are collinear or touch + if ( + in_array(self::ORIENTATION_COLLINEAR, $orientation, true) + && (new Intersection())->intersects($this, $line, false) + ) { + return true; + } + + // the lines do not overlap + return false; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Polygon.php b/admin/vendor/mjaschen/phpgeo/src/Polygon.php new file mode 100644 index 000000000..1582366f6 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Polygon.php @@ -0,0 +1,260 @@ + + */ + protected $points = []; + + /** + * @param Coordinate $point + * + * @return void + */ + public function addPoint(Coordinate $point): void + { + $this->points[] = $point; + } + + /** + * @param array $points + */ + public function addPoints(array $points): void + { + foreach ($points as $point) { + $this->addPoint($point); + } + } + + /** + * @return array + */ + public function getPoints(): array + { + return $this->points; + } + + /** + * Return all polygon point's latitudes. + * + * @return array + */ + public function getLats(): array + { + $lats = []; + + foreach ($this->points as $point) { + /** @var Coordinate $point */ + $lats[] = $point->getLat(); + } + + return $lats; + } + + /** + * Return all polygon point's longitudes. + * + * @return array + */ + public function getLngs(): array + { + $lngs = []; + + foreach ($this->points as $point) { + /** @var Coordinate $point */ + $lngs[] = $point->getLng(); + } + + return $lngs; + } + + /** + * @return int + */ + public function getNumberOfPoints(): int + { + return count($this->points); + } + + /** + * @param FormatterInterface $formatter + * + * @return string + */ + public function format(FormatterInterface $formatter): string + { + return $formatter->format($this); + } + + /** + * @return array + */ + public function getSegments(): array + { + $length = count($this->points); + $segments = []; + + if ($length <= 1) { + return $segments; + } + + for ($i = 1; $i < $length; $i++) { + $segments[] = new Line($this->points[$i - 1], $this->points[$i]); + } + + // to close the polygon we have to add the final segment between + // the last point and the first point + $segments[] = new Line($this->points[$i - 1], $this->points[0]); + + return $segments; + } + + /** + * Determine if given geometry is contained inside the polygon. This is + * assumed to be true, if each point of the geometry is inside the polygon. + * + * Edge cases: + * + * - it's not detected when a line between two points is outside the polygon + * - @see contains() for more restrictions + * + * @param GeometryInterface $geometry + * + * @return bool + */ + public function containsGeometry(GeometryInterface $geometry): bool + { + $geometryInPolygon = true; + + foreach ($geometry->getPoints() as $point) { + $geometryInPolygon = $geometryInPolygon && $this->contains($point); + } + + return $geometryInPolygon; + } + + /** + * Determine if given point is contained inside the polygon. Uses the PNPOLY + * algorithm by W. Randolph Franklin. Therfore some edge cases may not give the + * expected results, e.g. if the point resides on the polygon boundary. + * + * @see https://wrf.ecse.rpi.edu/Research/Short_Notes/pnpoly.html + * + * For special cases this calculation leads to wrong results: + * + * - if the polygons spans over the longitude boundaries at 180/-180 degrees + * + * @param Coordinate $point + * + * @return bool + */ + public function contains(Coordinate $point): bool + { + $numberOfPoints = $this->getNumberOfPoints(); + $polygonLats = $this->getLats(); + $polygonLngs = $this->getLngs(); + + $polygonContainsPoint = false; + + for ($node = 0, $altNode = $numberOfPoints - 1; $node < $numberOfPoints; $altNode = $node++) { + $condition = ($polygonLngs[$node] > $point->getLng()) !== ($polygonLngs[$altNode] > $point->getLng()) + && ($point->getLat() < ($polygonLats[$altNode] - $polygonLats[$node]) + * ($point->getLng() - $polygonLngs[$node]) + / ($polygonLngs[$altNode] - $polygonLngs[$node]) + $polygonLats[$node]); + + if ($condition) { + $polygonContainsPoint = !$polygonContainsPoint; + } + } + + return $polygonContainsPoint; + } + + /** + * Calculates the polygon perimeter. + * + * @param DistanceInterface $calculator instance of distance calculation class + * + * @return float + */ + public function getPerimeter(DistanceInterface $calculator): float + { + $perimeter = 0.0; + + if (count($this->points) < 2) { + return $perimeter; + } + + foreach ($this->getSegments() as $segment) { + $perimeter += $segment->getLength($calculator); + } + + return $perimeter; + } + + /** + * Calculates the polygon area. + * + * This algorithm gives inaccurate results as it ignores + * ellipsoid parameters other than to arithmetic mean radius. + * The error should be < 1 % for small areas. + * + * @return float + */ + public function getArea(): float + { + $area = 0; + + if ($this->getNumberOfPoints() <= 2) { + return $area; + } + + $referencePoint = $this->points[0]; + $radius = $referencePoint->getEllipsoid()->getArithmeticMeanRadius(); + $segments = $this->getSegments(); + + foreach ($segments as $segment) { + $point1 = $segment->getPoint1(); + $point2 = $segment->getPoint2(); + + $x1 = deg2rad($point1->getLng() - $referencePoint->getLng()) * cos(deg2rad($point1->getLat())); + $y1 = deg2rad($point1->getLat() - $referencePoint->getLat()); + + $x2 = deg2rad($point2->getLng() - $referencePoint->getLng()) * cos(deg2rad($point2->getLat())); + $y2 = deg2rad($point2->getLat() - $referencePoint->getLat()); + + $area += ($x2 * $y1 - $x1 * $y2); + } + + $area *= 0.5 * $radius ** 2; + + return abs($area); + } + + /** + * Create a new polygon with reversed order of points, i. e. reversed + * polygon direction. + * + * @return Polygon + */ + public function getReverse(): Polygon + { + $reversed = new self(); + + foreach (array_reverse($this->points) as $point) { + $reversed->addPoint($point); + } + + return $reversed; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Polyline.php b/admin/vendor/mjaschen/phpgeo/src/Polyline.php new file mode 100644 index 000000000..e703d95e3 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Polyline.php @@ -0,0 +1,197 @@ + + */ +class Polyline implements GeometryInterface +{ + use GetBoundsTrait; + + /** + * @var array + */ + protected $points = []; + + /** + * @param Coordinate $point + * + * @return void + */ + public function addPoint(Coordinate $point): void + { + $this->points[] = $point; + } + + /** + * @param array $points + */ + public function addPoints(array $points): void + { + foreach ($points as $point) { + $this->addPoint($point); + } + } + + /** + * Adds an unique point to the polyline. A maximum allowed distance for + * same point comparison can be provided. Default allowed distance + * deviation is 0.001 meters (1 millimeter). + * + * @param Coordinate $point + * @param float $allowedDistance + * + * @return void + */ + public function addUniquePoint(Coordinate $point, float $allowedDistance = .001): void + { + if ($this->containsPoint($point, $allowedDistance)) { + return; + } + + $this->addPoint($point); + } + + /** + * @return array + */ + public function getPoints(): array + { + return $this->points; + } + + /** + * @return int + */ + public function getNumberOfPoints(): int + { + return count($this->points); + } + + /** + * @param Coordinate $point + * @param float $allowedDistance + * + * @return bool + */ + public function containsPoint(Coordinate $point, float $allowedDistance = .001): bool + { + foreach ($this->points as $existingPoint) { + if ($existingPoint->hasSameLocation($point, $allowedDistance)) { + return true; + } + } + + return false; + } + + /** + * @param FormatterInterface $formatter + * + * @return string + */ + public function format(FormatterInterface $formatter): string + { + return $formatter->format($this); + } + + /** + * @return array + */ + public function getSegments(): array + { + $length = count($this->points); + $segments = []; + + if ($length <= 1) { + return $segments; + } + + for ($i = 1; $i < $length; $i++) { + $segments[] = new Line($this->points[$i - 1], $this->points[$i]); + } + + return $segments; + } + + /** + * Calculates the length of the polyline. + * + * @param DistanceInterface $calculator instance of distance calculation class + * + * @return float + */ + public function getLength(DistanceInterface $calculator): float + { + $distance = 0.0; + + if (count($this->points) <= 1) { + return $distance; + } + + foreach ($this->getSegments() as $segment) { + $distance += $segment->getLength($calculator); + } + + return $distance; + } + + /** + * Create a new polyline with reversed order of points, i. e. reversed + * polyline direction. + * + * @return Polyline + */ + public function getReverse(): Polyline + { + $reversed = new self(); + + foreach (array_reverse($this->points) as $point) { + $reversed->addPoint($point); + } + + return $reversed; + } + + /** + * Returns the point which is defined by the avarages of all + * latitude/longitude values. + * + * This currently only works for polylines which don't cross the dateline at + * 180/-180 degrees longitude. + * + * @return Coordinate + * + * @throws InvalidGeometryException when the polyline doesn't contain any points. + */ + public function getAveragePoint(): Coordinate + { + $latitude = 0.0; + $longitude = 0.0; + $numberOfPoints = count($this->points); + + if ($this->getNumberOfPoints() === 0) { + throw new InvalidGeometryException('Polyline doesn\'t contain points', 9464188927); + } + + foreach ($this->points as $point) { + // @var Coordinate $point + $latitude += $point->getLat(); + $longitude += $point->getLng(); + } + + $latitude /= $numberOfPoints; + $longitude /= $numberOfPoints; + + return new Coordinate($latitude, $longitude); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyBearing.php b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyBearing.php new file mode 100644 index 000000000..4e970c8a0 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyBearing.php @@ -0,0 +1,120 @@ + + */ +class SimplifyBearing implements SimplifyInterface +{ + /** + * @var float + */ + private $bearingAngle; + + /** + * SimplifyBearing constructor. + * + * @param float $bearingAngle + */ + public function __construct(float $bearingAngle) + { + $this->bearingAngle = $bearingAngle; + } + + /** + * @param Polyline $polyline + * + * @return Polyline + * @throws RuntimeException + */ + public function simplify(Polyline $polyline): Polyline + { + $result = $this->simplifyGeometry($polyline); + + if (!($result instanceof Polyline)) { + throw new RuntimeException('Result is no Polyline', 4231694400); + } + + return $result; + } + + /** + * Simplifies the given polyline + * + * 1. calculate the bearing angle between the first two points p1 and p2: b1 + * 2. calculate the bearing angle between the next two points p2 and p3: b2 + * 3. calculate the difference between b1 and b2: deltaB; if deltaB is + * smaller than the threshold angle, remove the middle point p2 + * 4. start again at (1.) as long as the polyline contains more points + * + * This method will be merged with `simplify()` in the next major release. + * + * @param GeometryInterface $geometry + * + * @return GeometryInterface + */ + public function simplifyGeometry(GeometryInterface $geometry): GeometryInterface + { + if (!($geometry instanceof Polyline) && !($geometry instanceof Polygon)) { + return $geometry; + } + + $counterPoints = $geometry->getNumberOfPoints(); + + if ($geometry instanceof Polygon) { + if ($counterPoints <= 3) { + return clone $geometry; + } + $result = new Polygon(); + } else { + if ($counterPoints < 3) { + return clone $geometry; + } + $result = new Polyline(); + } + + $bearingCalc = new BearingEllipsoidal(); + + $points = $geometry->getPoints(); + + $index = 0; + + // add the first point to the resulting polyline + $result->addPoint($points[$index]); + + do { + $index++; + + // preserve the last point of the original polyline + if ($index === $counterPoints - 1) { + $result->addPoint($points[$index]); + break; + } + + $bearing1 = $bearingCalc->calculateBearing($points[$index - 1], $points[$index]); + $bearing2 = $bearingCalc->calculateBearing($points[$index], $points[$index + 1]); + + $bearingDifference = min( + fmod($bearing1 - $bearing2 + 360, 360), + fmod($bearing2 - $bearing1 + 360, 360) + ); + + if ($bearingDifference > $this->bearingAngle) { + $result->addPoint($points[$index]); + } + } while ($index < $counterPoints); + + return $result; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyDouglasPeucker.php b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyDouglasPeucker.php new file mode 100644 index 000000000..40331e252 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyDouglasPeucker.php @@ -0,0 +1,135 @@ + + */ +class SimplifyDouglasPeucker implements SimplifyInterface +{ + /** + * @var float + */ + protected $tolerance; + + /** + * @param float $tolerance the perpendicular distance threshold in meters + */ + public function __construct(float $tolerance) + { + $this->tolerance = $tolerance; + } + + /** + * @param Polyline $polyline + * + * @return Polyline + * @throws RuntimeException + */ + public function simplify(Polyline $polyline): Polyline + { + $result = $this->simplifyGeometry($polyline); + + if (!($result instanceof Polyline)) { + throw new RuntimeException('Result is no Polyline', 9737647468); + } + + return $result; + } + + /** + * This method is a workaround to allow simplifying polygons too. It'll be + * merged with `simplify()` in the next major release. + * + * @param GeometryInterface $geometry + * + * @return GeometryInterface + */ + public function simplifyGeometry(GeometryInterface $geometry): GeometryInterface + { + if (!($geometry instanceof Polyline) && !($geometry instanceof Polygon)) { + return $geometry; + } + + $counterPoints = $geometry->getNumberOfPoints(); + + if ($geometry instanceof Polygon) { + if ($counterPoints <= 3) { + return clone $geometry; + } + $result = new Polygon(); + } else { + if ($counterPoints < 3) { + return clone $geometry; + } + $result = new Polyline(); + } + + $simplifiedLine = $this->douglasPeucker($geometry->getPoints()); + + $result->addPoints($simplifiedLine); + + return $result; + } + + /** + * @param array $line + * + * @return array + */ + protected function douglasPeucker(array $line): array + { + $distanceMax = 0; + $index = 0; + + $lineSize = count($line); + + $pdCalc = new PerpendicularDistance(); + + for ($i = 1; $i <= $lineSize - 2; $i++) { + $distance = $pdCalc->getPerpendicularDistance($line[$i], new Line($line[0], $line[$lineSize - 1])); + + if ($distance > $distanceMax) { + $index = $i; + $distanceMax = $distance; + } + } + + if ($distanceMax > $this->tolerance) { + $lineSplitFirst = array_slice($line, 0, $index + 1); + $lineSplitSecond = array_slice($line, $index, $lineSize - $index); + + $resultsSplit1 = count($lineSplitFirst) > 2 + ? $this->douglasPeucker($lineSplitFirst) + : $lineSplitFirst; + + $resultsSplit2 = count($lineSplitSecond) > 2 + ? $this->douglasPeucker($lineSplitSecond) + : $lineSplitSecond; + + array_pop($resultsSplit1); + + return array_merge($resultsSplit1, $resultsSplit2); + } + + return [$line[0], $line[$lineSize - 1]]; + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyInterface.php b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyInterface.php new file mode 100644 index 000000000..6c3a1fb3e --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Processor/Polyline/SimplifyInterface.php @@ -0,0 +1,24 @@ + + */ +interface SimplifyInterface +{ + /** + * Simplifies the given polyline + * + * @param Polyline $polyline + * + * @return Polyline + */ + public function simplify(Polyline $polyline): Polyline; +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Utility/Cartesian.php b/admin/vendor/mjaschen/phpgeo/src/Utility/Cartesian.php new file mode 100644 index 000000000..9ab2dcb12 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Utility/Cartesian.php @@ -0,0 +1,73 @@ +x = $x; + $this->y = $y; + $this->z = $z; + } + + /** + * @return float + */ + public function getX(): float + { + return $this->x; + } + + /** + * @return float + */ + public function getY(): float + { + return $this->y; + } + + /** + * @return float + */ + public function getZ(): float + { + return $this->z; + } + + /** + * @param Cartesian $other + * + * @return Cartesian + */ + public function add(Cartesian $other): Cartesian + { + return new self( + $this->x + $other->x, + $this->y + $other->y, + $this->z + $other->z + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Utility/PerpendicularDistance.php b/admin/vendor/mjaschen/phpgeo/src/Utility/PerpendicularDistance.php new file mode 100644 index 000000000..735553b32 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Utility/PerpendicularDistance.php @@ -0,0 +1,82 @@ + + */ +class PerpendicularDistance +{ + public function getPerpendicularDistance(Coordinate $point, Line $line): float + { + $ellipsoid = $point->getEllipsoid(); + + $ellipsoidRadius = $ellipsoid->getArithmeticMeanRadius(); + + $firstLinePointLat = $this->deg2radLatitude($line->getPoint1()->getLat()); + $firstLinePointLng = $this->deg2radLongitude($line->getPoint1()->getLng()); + + $firstLinePointX = $ellipsoidRadius * cos($firstLinePointLng) * sin($firstLinePointLat); + $firstLinePointY = $ellipsoidRadius * sin($firstLinePointLng) * sin($firstLinePointLat); + $firstLinePointZ = $ellipsoidRadius * cos($firstLinePointLat); + + $secondLinePointLat = $this->deg2radLatitude($line->getPoint2()->getLat()); + $secondLinePointLng = $this->deg2radLongitude($line->getPoint2()->getLng()); + + $secondLinePointX = $ellipsoidRadius * cos($secondLinePointLng) * sin($secondLinePointLat); + $secondLinePointY = $ellipsoidRadius * sin($secondLinePointLng) * sin($secondLinePointLat); + $secondLinePointZ = $ellipsoidRadius * cos($secondLinePointLat); + + $pointLat = $this->deg2radLatitude($point->getLat()); + $pointLng = $this->deg2radLongitude($point->getLng()); + + $pointX = $ellipsoidRadius * cos($pointLng) * sin($pointLat); + $pointY = $ellipsoidRadius * sin($pointLng) * sin($pointLat); + $pointZ = $ellipsoidRadius * cos($pointLat); + + $normalizedX = $firstLinePointY * $secondLinePointZ - $firstLinePointZ * $secondLinePointY; + $normalizedY = $firstLinePointZ * $secondLinePointX - $firstLinePointX * $secondLinePointZ; + $normalizedZ = $firstLinePointX * $secondLinePointY - $firstLinePointY * $secondLinePointX; + + $length = sqrt($normalizedX * $normalizedX + $normalizedY * $normalizedY + $normalizedZ * $normalizedZ); + + if ($length == 0.0) { + return 0; + } + + $normalizedX /= $length; + $normalizedY /= $length; + $normalizedZ /= $length; + + $thetaPoint = $normalizedX * $pointX + $normalizedY * $pointY + $normalizedZ * $pointZ; + + $length = sqrt($pointX * $pointX + $pointY * $pointY + $pointZ * $pointZ); + + $thetaPoint /= $length; + + $distance = abs((M_PI / 2) - acos($thetaPoint)); + + return $distance * $ellipsoidRadius; + } + + protected function deg2radLatitude(float $latitude): float + { + return deg2rad(90 - $latitude); + } + + protected function deg2radLongitude(float $longitude): float + { + if ($longitude > 0) { + return deg2rad($longitude); + } + + return deg2rad($longitude + 360); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/src/Utility/PointToLineDistance.php b/admin/vendor/mjaschen/phpgeo/src/Utility/PointToLineDistance.php new file mode 100644 index 000000000..77746a040 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/src/Utility/PointToLineDistance.php @@ -0,0 +1,88 @@ + + */ +class PointToLineDistance +{ + /** + * @var DistanceInterface + */ + private $distanceCalculator; + + /** + * @var float + */ + private $epsilon; + + public function __construct(DistanceInterface $distanceCalculator, float $epsilon = 0.001) + { + $this->distanceCalculator = $distanceCalculator; + $this->epsilon = $epsilon; + } + + /** + * @psalm-suppress InvalidReturnType + * @throws NotConvergingException + */ + public function getDistance(Coordinate $point, Line $line): float + { + if ($line->getPoint1()->hasSameLocation($line->getPoint2(), $this->epsilon)) { + return $this->distanceCalculator->getDistance($point, $line->getPoint1()); + } + if ($point->hasSameLocation($line->getPoint1(), $this->epsilon)) { + return 0.0; + } + if ($point->hasSameLocation($line->getPoint2(), $this->epsilon)) { + return 0.0; + } + if ($point->hasSameLocation($line->getMidpoint(), $this->epsilon)) { + return 0.0; + } + + $iterationsCounter = 0; + $iterationLine = clone $line; + + do { + $linePoint1 = $iterationLine->getPoint1(); + $linePoint2 = $iterationLine->getPoint2(); + $lineMidPoint = $iterationLine->getMidpoint(); + + $distancePointToLinePoint1 = $point->getDistance($linePoint1, $this->distanceCalculator); + $distancePointToLinePoint2 = $point->getDistance($linePoint2, $this->distanceCalculator); + + if ($distancePointToLinePoint1 <= $distancePointToLinePoint2) { + $iterationLine = new Line($linePoint1, $lineMidPoint); + } else { + $iterationLine = new Line($lineMidPoint, $linePoint2); + } + + if (abs($distancePointToLinePoint1 - $distancePointToLinePoint2) < $this->epsilon) { + return $point->getDistance($iterationLine->getMidpoint(), $this->distanceCalculator); + } + + $iterationsCounter++; + if ($iterationsCounter > 100) { + throw new NotConvergingException( + 'Calculation of Point to Minor Arc did not converge after 100 iterations.', + 6391878367 + ); + } + } while (true); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingEllipsoidalTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingEllipsoidalTest.php new file mode 100644 index 000000000..e00ae4109 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingEllipsoidalTest.php @@ -0,0 +1,212 @@ +assertEquals(0.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingSouthernWorksAsExpected(): void + { + $point1 = new Coordinate(10, 0); + $point2 = new Coordinate(0, 0); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(180.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(90.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, - 10); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(270.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingNorthEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0.1, 0.1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEqualsWithDelta(45.0, $bearingCalculator->calculateBearing($point1, $point2), 0.2, ''); + } + + public function testIfCalculateBearingNorthWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0.1, -0.1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEqualsWithDelta(315.0, $bearingCalculator->calculateBearing($point1, $point2), 0.2, ''); + } + + public function testIfCalculateBearingSouthEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(- 0.1, 0.1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEqualsWithDelta(135.0, $bearingCalculator->calculateBearing($point1, $point2), 0.2, ''); + } + + public function testIfCalculateBearingSouthWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(- 0.1, - 0.1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEqualsWithDelta(225.0, $bearingCalculator->calculateBearing($point1, $point2), 0.2, ''); + } + + public function testIfCalculateFinalBearingNorthernWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(10, 0); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(0.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingSouthernWorksAsExpected(): void + { + $point1 = new Coordinate(10, 0); + $point2 = new Coordinate(0, 0); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(180.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(90.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, - 10); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(270.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateDestinationEasternWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 90, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + // so we expect a latitude of 0 degrees and a longitude + // of 1 degree: + + $this->assertEqualsWithDelta(0.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(1.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationWesternWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 270, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(0.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(-1.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationNorthernWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 0, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationNorthern360WorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 360, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationSouthernWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 180, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(-1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfBearingForTheSamePointIsZero(): void + { + $bearingCalculator = new BearingEllipsoidal(); + $point1 = new Coordinate(50.12345, 10.23456); + $point2 = new Coordinate(50.12345, 10.23456); + + $this->assertEquals(0.0, $bearingCalculator->calculateBearing($point1, $point2)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingSphericalTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingSphericalTest.php new file mode 100644 index 000000000..e27c77dc8 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Bearing/BearingSphericalTest.php @@ -0,0 +1,203 @@ +assertEquals(0.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingSouthernWorksAsExpected(): void + { + $point1 = new Coordinate(10, 0); + $point2 = new Coordinate(0, 0); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(180.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(90.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, - 10); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(270.0, $bearingCalculator->calculateBearing($point1, $point2)); + } + + public function testIfCalculateBearingNorthEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0.1, 0.1); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEqualsWithDelta(45.0, $bearingCalculator->calculateBearing($point1, $point2), 0.1, ''); + } + + public function testIfCalculateBearingNorthWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0.1, - 0.1); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEqualsWithDelta(315.0, $bearingCalculator->calculateBearing($point1, $point2), 0.1, ''); + } + + public function testIfCalculateBearingSouthEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(- 0.1, 0.1); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEqualsWithDelta(135.0, $bearingCalculator->calculateBearing($point1, $point2), 0.1, ''); + } + + public function testIfCalculateBearingSouthWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(- 0.1, - 0.1); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEqualsWithDelta(225.0, $bearingCalculator->calculateBearing($point1, $point2), 0.1, ''); + } + + public function testIfCalculateFinalBearingNorthernWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(10, 0); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(0.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingSouthernWorksAsExpected(): void + { + $point1 = new Coordinate(10, 0); + $point2 = new Coordinate(0, 0); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(180.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingEasternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(90.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateFinalBearingWesternWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, - 10); + + $bearingCalculator = new BearingSpherical(); + + $this->assertEquals(270.0, $bearingCalculator->calculateFinalBearing($point1, $point2)); + } + + public function testIfCalculateDestinationEasternWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 90, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + // so we expect a latitude of 0 degrees and a longitude + // of 1 degree: + + $this->assertEqualsWithDelta(0.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(1.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationWesternWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 270, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(0.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(-1.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationNorthernWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 0, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationNorthern360WorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 360, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } + + public function testIfCalculateDestinationSouthernWorksAsExpected(): void + { + $bearingCalculator = new BearingSpherical(); + + $point = new Coordinate(0, 0); + $destination = $bearingCalculator->calculateDestination($point, 180, 111195.0837); + + // 1 degree in longitude at the equator: + // 2πr/360 = 40030230.1407 meters/360 = 111195.0837 meters + + $this->assertEqualsWithDelta(-1.0, $destination->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta(0.0, $destination->getLng(), 0.0001, ''); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/BoundsTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/BoundsTest.php new file mode 100644 index 000000000..3758c0f7e --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/BoundsTest.php @@ -0,0 +1,88 @@ +object = new Bounds( + new Coordinate(50, 10), + new Coordinate(30, 30) + ); + } + + protected function tearDown(): void + { + unset($this->object); + } + + public function testGetNortWest(): void + { + $c = new Coordinate(50, 10); + + $this->assertEquals($c, $this->object->getNorthWest()); + } + + public function testGetSouthEast(): void + { + $c = new Coordinate(30, 30); + + $this->assertEquals($c, $this->object->getSouthEast()); + } + + public function testGetNorth(): void + { + $this->assertEquals(50, $this->object->getNorth()); + } + + public function testGetSouth(): void + { + $this->assertEquals(30, $this->object->getSouth()); + } + + public function testGetWest(): void + { + $this->assertEquals(10, $this->object->getWest()); + } + + public function testGetEast(): void + { + $this->assertEquals(30, $this->object->getEast()); + } + + public function testGetCenter(): void + { + $testBounds = [ + ['nw' => new Coordinate(50, 10), 'se' => new Coordinate(30, 30), 'c' => new Coordinate(40, 20)], + ['nw' => new Coordinate(50, - 130), 'se' => new Coordinate(30, - 110), 'c' => new Coordinate(40, - 120)], + ['nw' => new Coordinate(10, - 10), 'se' => new Coordinate(- 10, 10), 'c' => new Coordinate(0, 0)], + [ + 'nw' => new Coordinate(- 80, - 130), + 'se' => new Coordinate(- 90, - 110), + 'c' => new Coordinate(- 85, - 120) + ], + ['nw' => new Coordinate(80, - 130), 'se' => new Coordinate(90, - 110), 'c' => new Coordinate(85, - 120)], + ['nw' => new Coordinate(80, 110), 'se' => new Coordinate(90, 130), 'c' => new Coordinate(85, 120)], + ['nw' => new Coordinate(50, 170), 'se' => new Coordinate(30, - 160), 'c' => new Coordinate(40, - 175)], + ['nw' => new Coordinate(- 50, 150), 'se' => new Coordinate(- 70, - 170), 'c' => new Coordinate(- 60, 170)], + ]; + + foreach ($testBounds as $bounds) { + $b = new Bounds($bounds['nw'], $bounds['se']); + + $this->assertEquals($bounds['c'], $b->getCenter()); + } + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesCalculatorTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesCalculatorTest.php new file mode 100644 index 000000000..0b8f7b7e9 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesCalculatorTest.php @@ -0,0 +1,120 @@ +assertEquals( + $expected, + $cardinalDirectionDistancesCalculator->getCardinalDirectionDistances($point1, $point2, new Vincenty()) + ); + } + + public function getCardinalDirectionDistancesProvider(): Generator + { + $point2 = new Coordinate(51, 13); + + $directDistanceWestEast = 70197.14; + + yield 'point1 equals point2' => [ + 'point1' => $point2, + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create(), + ]; + yield 'point1 north from point2' => [ + 'point1' => $this->moveToNorth($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setSouth(111257.827), + ]; + yield 'point1 east from point2' => [ + 'point1' => $this->moveToEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setWest($directDistanceWestEast), + ]; + yield 'point1 south from point2' => [ + 'point1' => $this->moveToSouth($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setNorth(111238.681), + ]; + yield 'point1 west from point2' => [ + 'point1' => $this->moveToWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setEast($directDistanceWestEast), + ]; + yield 'point1 north west from point2' => [ + 'point1' => $this->moveToNorthWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setEast(68677.475)->setSouth(111257.827), + ]; + yield 'point1 north east from point2' => [ + 'point1' => $this->moveToNorthEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setSouth(111257.827)->setWest(68677.475), + ]; + yield 'point1 south east from point2' => [ + 'point1' => $this->moveToSouthEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setNorth(111238.681)->setWest(71695.22), + ]; + yield 'point1 south west from point2' => [ + 'point1' => $this->moveToSouthWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirectionDistances::create()->setNorth(111238.681)->setEast(71695.22), + ]; + } + + private function moveToNorth(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat() + 1, $coordinate->getLng()); + } + + private function moveToEast(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat(), $coordinate->getLng() + 1); + } + + private function moveToSouth(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat() - 1, $coordinate->getLng()); + } + + private function moveToWest(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat(), $coordinate->getLng() - 1); + } + + private function moveToNorthEast(Coordinate $coordinate): Coordinate + { + return self::moveToNorth(self::moveToEast($coordinate)); + } + + private function moveToSouthEast(Coordinate $coordinate): Coordinate + { + return self::moveToSouth(self::moveToEast($coordinate)); + } + + private function moveToSouthWest(Coordinate $coordinate): Coordinate + { + return self::moveToSouth(self::moveToWest($coordinate)); + } + + private function moveToNorthWest(Coordinate $coordinate): Coordinate + { + return self::moveToNorth(self::moveToWest($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesTest.php new file mode 100644 index 000000000..9fa180882 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionDistancesTest.php @@ -0,0 +1,77 @@ +assertSame($north, CardinalDirectionDistances::create()->setNorth($north)->getNorth()); + } + + public function testSetNorthThrows(): void + { + $this->expectException(InvalidDistanceException::class); + CardinalDirectionDistances::create()->setNorth(-1); + } + + public function testSetEast(): void + { + $east = 2500.0; + $this->assertSame($east, CardinalDirectionDistances::create()->setEast($east)->getEast()); + } + + public function testSetEastThrows(): void + { + $this->expectException(InvalidDistanceException::class); + CardinalDirectionDistances::create()->setEast(-1); + } + + public function testSetSouth(): void + { + $south = 2500.0; + $this->assertSame($south, CardinalDirectionDistances::create()->setSouth($south)->getSouth()); + } + + public function testSetSouthThrows(): void + { + $this->expectException(InvalidDistanceException::class); + CardinalDirectionDistances::create()->setSouth(-1); + } + + public function testSetWest(): void + { + $west = 2500.0; + $this->assertSame($west, CardinalDirectionDistances::create()->setWest($west)->getWest()); + } + + public function testSetWestThrows(): void + { + $this->expectException(InvalidDistanceException::class); + CardinalDirectionDistances::create()->setWest(-1); + } + + public function testSetMultiple(): void + { + $north = 500.0; + $east = 1000.0; + $south = 1500.0; + $west = 2000.0; + $cardinalDirectionDistances = CardinalDirectionDistances::create() + ->setNorth($north) + ->setEast($east) + ->setSouth($south) + ->setWest($west); + + $this->assertSame($north, $cardinalDirectionDistances->getNorth()); + $this->assertSame($east, $cardinalDirectionDistances->getEast()); + $this->assertSame($south, $cardinalDirectionDistances->getSouth()); + $this->assertSame($west, $cardinalDirectionDistances->getWest()); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionTest.php new file mode 100644 index 000000000..dfe83c2ea --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/CardinalDirection/CardinalDirectionTest.php @@ -0,0 +1,111 @@ +assertSame( + $expected, + (new CardinalDirection())->getCardinalDirection($point1, $point2) + ); + } + + public function getCardinalDirectionProvider(): Generator + { + $point2 = new Coordinate(51, 13); + yield 'point1 equals point2' => [ + 'point1' => $point2, + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_NONE, + ]; + yield 'point1 north from point2' => [ + 'point1' => $this->moveToNorth($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_NORTH, + ]; + yield 'point1 east from point2' => [ + 'point1' => $this->moveToEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_EAST, + ]; + yield 'point1 south from point2' => [ + 'point1' => $this->moveToSouth($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_SOUTH, + ]; + yield 'point1 west from point2' => [ + 'point1' => $this->moveToWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_WEST, + ]; + yield 'point1 north west from point2' => [ + 'point1' => $this->moveToNorthWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_NORTHWEST, + ]; + yield 'point1 north east from point2' => [ + 'point1' => $this->moveToNorthEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_NORTHEAST, + ]; + yield 'point1 south east from point2' => [ + 'point1' => $this->moveToSouthEast($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_SOUTHEAST, + ]; + yield 'point1 south west from point2' => [ + 'point1' => $this->moveToSouthWest($point2), + 'point2' => $point2, + 'expected' => CardinalDirection::CARDINAL_DIRECTION_SOUTHWEST, + ]; + } + + private function moveToNorth(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat() + 1, $coordinate->getLng()); + } + + private function moveToEast(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat(), $coordinate->getLng() + 1); + } + + private function moveToSouth(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat() - 1, $coordinate->getLng()); + } + + private function moveToWest(Coordinate $coordinate): Coordinate + { + return new Coordinate($coordinate->getLat(), $coordinate->getLng() - 1); + } + + private function moveToNorthEast(Coordinate $coordinate): Coordinate + { + return self::moveToNorth(self::moveToEast($coordinate)); + } + + private function moveToSouthEast(Coordinate $coordinate): Coordinate + { + return self::moveToSouth(self::moveToEast($coordinate)); + } + + private function moveToSouthWest(Coordinate $coordinate): Coordinate + { + return self::moveToSouth(self::moveToWest($coordinate)); + } + + private function moveToNorthWest(Coordinate $coordinate): Coordinate + { + return self::moveToNorth(self::moveToWest($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/CoordinateTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/CoordinateTest.php new file mode 100644 index 000000000..0421df9f3 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/CoordinateTest.php @@ -0,0 +1,134 @@ + 'WGS-84', + 'a' => 6378137.0, + 'f' => 298.257223563, + ]; + + $this->ellipsoid = Ellipsoid::createFromArray($ellipsoidConfig); + + $this->coordinate = new Coordinate(52.5, 13.5, $this->ellipsoid); + } + + public function testConstructorInvalidLatitudeOutOfBoundsWorksAsExpected(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Latitude value must be numeric -90.0 .. +90.0 (given: 91)'); + + $c = new Coordinate(91.0, 13.5, $this->ellipsoid); + } + + public function testConstructorInvalidLongitudeOutOfBoundsWorksAsExpected(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Longitude value must be numeric -180.0 .. +180.0 (given: 190)'); + + $c = new Coordinate(52.2, 190.0, $this->ellipsoid); + } + + public function testConstructorBoundChecksWorkAsExpected(): void + { + $c = new Coordinate(90.0, 180.0, $this->ellipsoid); + + $this->assertEquals(90.0, $c->getLat()); + $this->assertEquals(180.0, $c->getLng()); + + $c = new Coordinate(-90.0, -180.0, $this->ellipsoid); + + $this->assertEquals(-90.0, $c->getLat()); + $this->assertEquals(-180.0, $c->getLng()); + + $c = new Coordinate(-90, 180, $this->ellipsoid); + + $this->assertEquals(-90.0, $c->getLat()); + $this->assertEquals(180.0, $c->getLng()); + + $c = new Coordinate(90, -180, $this->ellipsoid); + + $this->assertEquals(90.0, $c->getLat()); + $this->assertEquals(-180.0, $c->getLng()); + } + + public function testConstructorDefaultEllipsoid(): void + { + $c = new Coordinate(52.5, 13.5); + + $this->assertInstanceOf(Ellipsoid::class, $c->getEllipsoid()); + } + + public function testGetLat(): void + { + $this->assertEquals(52.5, $this->coordinate->getLat()); + } + + public function testGetLng(): void + { + $this->assertEquals(13.5, $this->coordinate->getLng()); + } + + public function testGetEllipsoid(): void + { + $this->assertEquals($this->ellipsoid, $this->coordinate->getEllipsoid()); + } + + public function testGetdistance(): void + { + $coordinate1 = new Coordinate(19.820664, -155.468066, $this->ellipsoid); + $coordinate2 = new Coordinate(20.709722, -156.253333, $this->ellipsoid); + + $this->assertEquals(128130.850, $coordinate1->getDistance($coordinate2, new Vincenty())); + } + + public function testFormat(): void + { + $this->assertEquals('52.50000 13.50000', $this->coordinate->format(new DecimalDegrees())); + } + + public function testHasSameLocation(): void + { + $point1 = new Coordinate(0.0, 0.0); + $point2 = new Coordinate(0.0, 0.0); + + $this->assertTrue($point1->hasSameLocation($point1, 0.0)); + $this->assertTrue($point1->hasSameLocation($point1, 0.1)); + + $this->assertTrue($point1->hasSameLocation($point2, 0.0)); + $this->assertTrue($point1->hasSameLocation($point2, 0.1)); + + $this->assertTrue($point2->hasSameLocation($point1, 0.0)); + $this->assertTrue($point2->hasSameLocation($point1, 0.1)); + + // distance: 1 arc second + $point2 = new Coordinate(0, 0.0002777778); + + $this->assertFalse($point1->hasSameLocation($point2, 0.0)); + + // a longitude difference of 1 arc second is about ~30.9 meters on the equator line + $this->assertFalse($point1->hasSameLocation($point2, 30.85)); + $this->assertTrue($point1->hasSameLocation($point2, 30.95)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Direction/DirectionTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Direction/DirectionTest.php new file mode 100644 index 000000000..d9651c46a --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Direction/DirectionTest.php @@ -0,0 +1,41 @@ +assertTrue((new Direction())->pointIsNorthOf(new Coordinate(50, 13), new Coordinate(40, 10))); + $this->assertTrue((new Direction())->pointIsNorthOf(new Coordinate(-50, 13), new Coordinate(-60, 10))); + $this->assertTrue((new Direction())->pointIsNorthOf(new Coordinate(10, 13), new Coordinate(-40, 10))); + } + + public function testIsSouthOf(): void + { + $this->assertTrue((new Direction())->pointIsSouthOf(new Coordinate(40, 10), new Coordinate(50, 13))); + $this->assertTrue((new Direction())->pointIsSouthOf(new Coordinate(-60, 10), new Coordinate(-50, 13))); + $this->assertTrue((new Direction())->pointIsSouthOf(new Coordinate(-40, 10), new Coordinate(10, 13))); + } + + public function testIsWestOf(): void + { + $this->assertTrue((new Direction())->pointIsWestOf(new Coordinate(40, 10), new Coordinate(50, 13))); + $this->assertTrue((new Direction())->pointIsWestOf(new Coordinate(-60, -10), new Coordinate(-50, -3))); + $this->assertTrue((new Direction())->pointIsWestOf(new Coordinate(-40, -100), new Coordinate(10, 130))); + $this->assertTrue((new Direction())->pointIsWestOf(new Coordinate(-40, -179), new Coordinate(10, 179))); + } + + public function testIsEastOf(): void + { + $this->assertTrue((new Direction())->pointIsEastOf(new Coordinate(50, 13), new Coordinate(40, 10))); + $this->assertTrue((new Direction())->pointIsEastOf(new Coordinate(-50, -3), new Coordinate(-60, -10))); + $this->assertTrue((new Direction())->pointIsEastOf(new Coordinate(10, 130), new Coordinate(-40, -100))); + $this->assertTrue((new Direction())->pointIsEastOf(new Coordinate(10, 179), new Coordinate(-40, -179))); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/HaversineTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/HaversineTest.php new file mode 100644 index 000000000..e19500192 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/HaversineTest.php @@ -0,0 +1,89 @@ + 'WGS-84', + 'a' => 6378137.0, + 'f' => 298.257223563, + ]; + + $this->ellipsoid = Ellipsoid::createFromArray($ellipsoidConfig); + + $this->calculator = new Haversine(); + } + + public function testGetDistanceZero(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.5, 13.5, $this->ellipsoid); + + $distance = $this->calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(0.0, $distance); + } + + public function testGetDistanceSameLatitude(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.5, 13.1, $this->ellipsoid); + + $distance = $this->calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(27076.476, $distance); + } + + public function testGetDistanceSameLongitude(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.1, 13.5, $this->ellipsoid); + + $distance = $this->calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(44478.032, $distance); + } + + public function testGetDistance(): void + { + $coordinate1 = new Coordinate(19.820664, - 155.468066, $this->ellipsoid); + $coordinate2 = new Coordinate(20.709722, - 156.253333, $this->ellipsoid); + + $distance = $this->calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(128384.515, $distance); + } + + public function testGetDistanceInternationalDateLine(): void + { + $coordinate1 = new Coordinate(20.0, 170.0, $this->ellipsoid); + $coordinate2 = new Coordinate(- 20.0, - 170.0, $this->ellipsoid); + + $distance = $this->calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(4952349.639, $distance); + } + + public function testNotMatchingEllipsoids(): void + { + $this->expectException(NotMatchingEllipsoidException::class); + + $coordinate1 = new Coordinate(19.820664, - 155.468066, $this->ellipsoid); + $coordinate2 = new Coordinate(20.709722, - 156.253333, new Ellipsoid('AnotherEllipsoid', 6378140.0, 299.2)); + + $this->calculator->getDistance($coordinate1, $coordinate2); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/VincentyTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/VincentyTest.php new file mode 100644 index 000000000..8d6a6dd39 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Distance/VincentyTest.php @@ -0,0 +1,92 @@ + 'WGS-84', + 'a' => 6378137.0, + 'f' => 298.257223563, + ]; + + $this->ellipsoid = Ellipsoid::createFromArray($ellipsoidConfig); + } + + public function testGetDistanceZero(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.5, 13.5, $this->ellipsoid); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(0.0, $distance); + } + + public function testGetDistanceSameLatitude(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.5, 13.1, $this->ellipsoid); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(27164.059, $distance); + } + + public function testGetDistanceSameLongitude(): void + { + $coordinate1 = new Coordinate(52.5, 13.5, $this->ellipsoid); + $coordinate2 = new Coordinate(52.1, 13.5, $this->ellipsoid); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(44509.218, $distance); + } + + public function testGetDistance(): void + { + $coordinate1 = new Coordinate(19.820664, - 155.468066, $this->ellipsoid); + $coordinate2 = new Coordinate(20.709722, - 156.253333, $this->ellipsoid); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(128130.850, $distance); + } + + public function testGetDistanceInternationalDateLine(): void + { + $coordinate1 = new Coordinate(20.0, 170.0, $this->ellipsoid); + $coordinate2 = new Coordinate(- 20.0, - 170.0, $this->ellipsoid); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + + $this->assertEquals(4932842.135, $distance); + } + + public function testNotMatchingEllispoids(): void + { + $this->expectException(NotMatchingEllipsoidException::class); + + $coordinate1 = new Coordinate(19.820664, - 155.468066, $this->ellipsoid); + $coordinate2 = new Coordinate(20.709722, - 156.253333, new Ellipsoid('AnotherEllipsoid', 6378140.0, 299.2)); + + $calculator = new Vincenty(); + $distance = $calculator->getDistance($coordinate1, $coordinate2); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/BoundsFactoryTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/BoundsFactoryTest.php new file mode 100644 index 000000000..eed7041ed --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/BoundsFactoryTest.php @@ -0,0 +1,95 @@ +assertEquals( + new Bounds( + new Coordinate(52.00063591099075, 12.998967101997957), + new Coordinate(51.999364079975535, 13.001032898002041) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 100, new BearingSpherical()) + ); + $this->assertEquals( + new Bounds( + new Coordinate(52.00063549793861, 12.998970388437384), + new Coordinate(51.99936449299343, 13.001029582403508) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 100, new BearingEllipsoidal()) + ); + + $startCenter = new Coordinate(-52, -13); + $this->assertEquals( + new Bounds( + new Coordinate(-51.999364079975535, -13.001032898002041), + new Coordinate(-52.00063591099075, -12.998967101997957) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 100, new BearingSpherical()) + ); + $this->assertEquals( + new Bounds( + new Coordinate(-51.99936449299343, -13.001029582403508), + new Coordinate(-52.00063549793861, -12.998970388437384) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 100, new BearingEllipsoidal()) + ); + } + + public function testIfExpandFromCenterCoordinateWorksWithNegativeDistance() + { + $startCenter = new Coordinate(52, 13); + $this->assertEquals( + new Bounds( + new Coordinate(51.999364079975535, 13.001032898002041), + new Coordinate(52.00063591099075, 12.998967101997957) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, -100, new BearingSpherical()) + ); + $this->assertEquals( + new Bounds( + new Coordinate(51.99936449299343, 13.001029582403508), + new Coordinate(52.00063549793861, 12.998970388437384) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, -100, new BearingEllipsoidal()) + ); + } + + public function testIfExpandFromCenterCoordinateThrowsExceptionOn180meridianWithBearingSpherical() + { + $this->expectException(InvalidArgumentException::class); + + $startCenter = new Coordinate(52, 179.999); + $this->assertEquals( + new Bounds( + new Coordinate(52.00063591099075, 12.998967101997957), + new Coordinate(51.999364079975535, 13.001032898002041) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 1000, new BearingSpherical()) + ); + } + + public function testIfExpandFromCenterCoordinateWorksOn180meridianWithBearingEllipsoidal() + { + $startCenter = new Coordinate(52, 179.999); + $this->assertEquals( + new Bounds( + new Coordinate(52.00635457125255, 179.98870257203671), + new Coordinate(51.993644521951445, -179.99070548794623) + ), + BoundsFactory::expandFromCenterCoordinate($startCenter, 1000, new BearingEllipsoidal()) + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/CoordinateFactoryTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/CoordinateFactoryTest.php new file mode 100644 index 000000000..c26db7cc1 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Factory/CoordinateFactoryTest.php @@ -0,0 +1,411 @@ +assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('52, 13')); + $this->assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('52 13')); + $this->assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('52 013')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5, 13.5')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5 13.5')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5°, 13.5°')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5° 13.5°')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5° 013.5°')); + $this->assertEquals(new Coordinate(-52.5, 13.5), CoordinateFactory::fromString('-52.5, 13.5')); + $this->assertEquals(new Coordinate(-52.5, 13.5), CoordinateFactory::fromString('-52.5 13.5')); + $this->assertEquals(new Coordinate(-52.5, 13.5), CoordinateFactory::fromString('-52.5 013.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('-52.5, -13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('-52.5 -13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('-52.5 -013.5')); + $this->assertEquals(new Coordinate(52.5, -13.5), CoordinateFactory::fromString('52.5, -13.5')); + $this->assertEquals(new Coordinate(52.5, -13.5), CoordinateFactory::fromString('52.5 -13.5')); + } + + public function testIfFromStringForDecimalDegreesWithCardinalLettersWorksAsExpected(): void + { + $this->assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('N52, E13')); + $this->assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('N52 E13')); + $this->assertEquals(new Coordinate(52, 13), CoordinateFactory::fromString('N52 E013')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('N52.5, E13.5')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('N52.5 E13.5')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('N52.5°, E13.5°')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('N52.5° E13.5°')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('N52.5° E013.5°')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5N, 13.5E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5N 13.5E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5N 013.5E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5°N, 13.5°E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5°N 13.5°E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5°N 013.5°E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5° N, 13.5° E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5° N 13.5° E')); + $this->assertEquals(new Coordinate(52.5, 13.5), CoordinateFactory::fromString('52.5° N 013.5° E')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('S52.5, W13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('S52.5 W13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5S, 13.5W')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5S 13.5W')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5S 013.5W')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('S 52.5, W 13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('S 52.5 W 13.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('S 52.5 W 013.5')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5 S, 13.5 W')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5 S 13.5 W')); + $this->assertEquals(new Coordinate(-52.5, -13.5), CoordinateFactory::fromString('52.5 S 013.5 W')); + } + + public function testIfFromStringWithDecimalMinutesWorksAsExpected(): void + { + $expected = new Coordinate(52.20575, 13.576116667); + $expectedLat = $expected->getLat(); + $expectedLng = $expected->getLng(); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52 12.345, 13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52 12.345, 13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + -$expectedLat, + CoordinateFactory::fromString('-52 12.345, 13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('-52 12.345, 13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + -$expectedLat, + CoordinateFactory::fromString('-52 12.345, -13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + -$expectedLng, + CoordinateFactory::fromString('-52 12.345, -13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52 12.345, -13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + -$expectedLng, + CoordinateFactory::fromString('52 12.345, -13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52° 12.345, 13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52° 12.345, 13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + -$expectedLat, + CoordinateFactory::fromString('-52° 12.345, 13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('-52° 12.345, 13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + -$expectedLat, + CoordinateFactory::fromString('-52° 12.345, -13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + -$expectedLng, + CoordinateFactory::fromString('-52° 12.345, -13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52° 12.345, -13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + -$expectedLng, + CoordinateFactory::fromString('52° 12.345, -13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N52 12.345, E13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N52 12.345, E13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N 52 12.345, E 13 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N 52 12.345, E 13 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52 12.345N, E13 34.567E')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52 12.345N, E13 34.567E')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52 12.345 N, E13 34.567 E')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52 12.345 N, E13 34.567 E')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N52° 12.345, E13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N52° 12.345, E13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N 52° 12.345, E 13° 34.567')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N 52° 12.345, E 13° 34.567')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52° 12.345N, E13° 34.567E')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52° 12.345N, E13° 34.567E')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52° 12.345 N, E13° 34.567 E')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52° 12.345 N, E13° 34.567 E')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString("N52° 12.345', E13° 34.567'")->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString("N52° 12.345', E13° 34.567'")->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString("N 52° 12.345', E 13° 34.567'")->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString("N 52° 12.345', E 13° 34.567'")->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString("52° 12.345' N, E13° 34.567' E")->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString("52° 12.345' N, E13° 34.567' E")->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N52° 12.345′, E13° 34.567′')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N52° 12.345′, E13° 34.567′')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('N 52° 12.345′, E 13° 34.567′')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('N 52° 12.345′, E 13° 34.567′')->getLng(), + 0.0001, + '' + ); + + $this->assertEqualsWithDelta( + $expectedLat, + CoordinateFactory::fromString('52° 12.345′ N, E13° 34.567′ E')->getLat(), + 0.0001, + '' + ); + $this->assertEqualsWithDelta( + $expectedLng, + CoordinateFactory::fromString('52° 12.345′ N, E13° 34.567′ E')->getLng(), + 0.0001, + '' + ); + + $this->assertEquals( + new Coordinate(52.2333, 20.9756), + CoordinateFactory::fromString('52° 13.998′ 020° 58.536′') + ); + } + + /** + * @dataProvider dataIfFromStringWithIntegerMinutesAndDecimalSecondsWorksAsExpected + * + * @param float $expectedLat + * @param float $expectedLng + * @param string $string + */ + public function testIfFromStringWithIntegerMinutesAndDecimalSecondsWorksAsExpected( + $expectedLat, + $expectedLng, + $string + ): void { + $coordinate = CoordinateFactory::fromString($string); + $this->assertEqualsWithDelta($expectedLat, $coordinate->getLat(), 0.0001, ''); + $this->assertEqualsWithDelta($expectedLng, $coordinate->getLng(), 0.0001, ''); + } + + /** + * Data provider for decimal seconds parser test. + */ + public function dataIfFromStringWithIntegerMinutesAndDecimalSecondsWorksAsExpected(): ?Generator + { + $expected = new Coordinate(52.20575, 13.576116667); + $expectedLat = $expected->getLat(); + $expectedLng = $expected->getLng(); + + $testData = [ + '52 12 20.7, 13 34 34.02', + '52 12 20.7N, 13 34 34.02E', + '52 12 20.7 N, E13 34 34.02 E', + '52° 12\' 20.7" N, E13° 34\' 34.02" E', + '52° 12\' 20.7\'\' N, E13° 34\' 34.02\'\' E', + '52° 12′ 20.7″ N, E13° 34′ 34.02″ E', + '52° 12′ 20.7′′ N, E13° 34′ 34.02′′ E', + ]; + + foreach ($testData as $string) { + yield $string => [$expectedLat, $expectedLng, $string]; + } + } + + public function testIfInvalidFormatThrowsException(): void + { + $this->expectException(InvalidArgumentException::class); + + CoordinateFactory::fromString('Lorem ipsum dolor sit amet'); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DMSTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DMSTest.php new file mode 100644 index 000000000..893355137 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DMSTest.php @@ -0,0 +1,96 @@ +formatter = new DMS(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + } + + public function testSetUnitsUTF8(): void + { + $this->formatter->setUnits(DMS::UNITS_UTF8); + + $this->assertEquals(DMS::UNITS_UTF8, $this->formatter->getUnitType()); + } + + public function testSetUnitsASCII(): void + { + $this->formatter->setUnits(DMS::UNITS_ASCII); + + $this->assertEquals(DMS::UNITS_ASCII, $this->formatter->getUnitType()); + } + + public function testSetUnitsInvalidType(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid unit type'); + + + $this->formatter->setUnits('invalid'); + } + + public function testFormatDefaultSeparator(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $this->assertEquals('52° 30′ 00″ 013° 30′ 00″', $this->formatter->format($coordinate)); + } + + public function testFormatCustomSeparator(): void + { + $coordinate = new Coordinate(18.911306, - 155.678268); + + $this->formatter->setSeparator(', '); + + $this->assertEquals('18° 54′ 41″, -155° 40′ 42″', $this->formatter->format($coordinate)); + } + + public function testFormatCardinalLetters(): void + { + $coordinate = new Coordinate(18.911306, - 155.678268); + + $this->formatter->setSeparator(', ')->useCardinalLetters(true); + + $this->assertEquals('18° 54′ 41″ N, 155° 40′ 42″ W', $this->formatter->format($coordinate)); + } + + public function testFormatBothNegative(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setSeparator(', '); + + $this->assertEquals('-18° 54′ 41″, -155° 40′ 42″', $this->formatter->format($coordinate)); + } + + public function testFormatASCIIUnits(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setSeparator(', ')->setUnits(DMS::UNITS_ASCII); + + $this->assertEquals("-18° 54' 41\", -155° 40' 42\"", $this->formatter->format($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalDegreesTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalDegreesTest.php new file mode 100644 index 000000000..a1127a0b3 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalDegreesTest.php @@ -0,0 +1,57 @@ +object = new DecimalDegrees(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + } + + public function testFormatDefaultSeparator(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $formatter = new DecimalDegrees(); + + $this->assertEquals('52.50000 13.50000', $formatter->format($coordinate)); + } + + public function testFormatCustomSeparator(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $formatter = new DecimalDegrees(', '); + + $this->assertEquals('52.50000, 13.50000', $formatter->format($coordinate)); + } + + public function testIfSetSeparatorWorksAsExpected(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $formatter = new DecimalDegrees(); + $formatter->setSeparator('/'); + + $this->assertEquals('52.50000/13.50000', $formatter->format($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalMinutesTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalMinutesTest.php new file mode 100644 index 000000000..8a0e9efa5 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/DecimalMinutesTest.php @@ -0,0 +1,113 @@ +formatter = new DecimalMinutes(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + } + + public function testSetUnitsUTF8(): void + { + $this->formatter->setUnits(DMS::UNITS_UTF8); + + $this->assertEquals(DMS::UNITS_UTF8, $this->formatter->getUnitType()); + } + + public function testSetUnitsASCII(): void + { + $this->formatter->setUnits(DMS::UNITS_ASCII); + + $this->assertEquals(DMS::UNITS_ASCII, $this->formatter->getUnitType()); + } + + public function testSetUnitsInvalidType(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid unit type'); + + $this->formatter->setUnits('invalid'); + } + + public function testFormatDefaultSeparator(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $this->assertEquals('52° 30.000′ 013° 30.000′', $this->formatter->format($coordinate)); + } + + public function testFormatCustomSeparator(): void + { + $coordinate = new Coordinate(18.911306, - 155.678268); + + $this->formatter->setSeparator(', '); + + $this->assertEquals('18° 54.678′, -155° 40.696′', $this->formatter->format($coordinate)); + } + + public function testFormatCardinalLetters(): void + { + $coordinate = new Coordinate(18.911306, - 155.678268); + + $this->formatter->setSeparator(', ')->useCardinalLetters(true); + + $this->assertEquals('18° 54.678′ N, 155° 40.696′ W', $this->formatter->format($coordinate)); + } + + public function testFormatBothNegative(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setSeparator(', '); + + $this->assertEquals('-18° 54.678′, -155° 40.696′', $this->formatter->format($coordinate)); + } + + public function testFormatASCIIUnits(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setSeparator(', ')->setUnits(DMS::UNITS_ASCII); + + $this->assertEquals("-18° 54.678', -155° 40.696'", $this->formatter->format($coordinate)); + } + + public function testSetDigits(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setDigits(2); + + $this->assertEquals('-18° 54.68′ -155° 40.70′', $this->formatter->format($coordinate)); + } + + public function testSetDecimalPoint(): void + { + $coordinate = new Coordinate(- 18.911306, - 155.678268); + + $this->formatter->setDecimalPoint(','); + + $this->assertEquals('-18° 54,678′ -155° 40,696′', $this->formatter->format($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/GeoJSONTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/GeoJSONTest.php new file mode 100644 index 000000000..ef899d4d1 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Coordinate/GeoJSONTest.php @@ -0,0 +1,52 @@ +formatter = new GeoJSON(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + unset($this->formatter); + } + + public function testFormatDefault(): void + { + $coordinate = new Coordinate(52.5, 13.5); + + $json = '{ "type" : "Point" , "coordinates" : [ 13.5, 52.5 ] }'; + + $this->assertJsonStringEqualsJsonString($json, $this->formatter->format($coordinate)); + } + + public function testFormatPrecision(): void + { + $coordinate = new Coordinate(52.123456789012345, 13.123456789012345); + + $json = '{ "type" : "Point" , "coordinates" : [ 13.123456789012345, 52.123456789012345 ] }'; + + $this->assertJsonStringEqualsJsonString($json, $this->formatter->format($coordinate)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polygon/GeoJSONTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polygon/GeoJSONTest.php new file mode 100644 index 000000000..c3e8a1d91 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polygon/GeoJSONTest.php @@ -0,0 +1,60 @@ +formatter = new GeoJSON(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + unset($this->formatter); + } + + public function testFormatDefault(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(20, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $json = '{ "type" : "Polygon" , "coordinates" : [ [ [ 20, 10 ], [ 40, 20 ], [ 40, 30 ], [ 20, 30] ] ] }'; + + $this->assertJsonStringEqualsJsonString($json, $this->formatter->format($polygon)); + } + + public function testPolygonGeoJSONWithLessThanThreePointsThrowsInvalidPolygonException(): void + { + $this->expectException(InvalidPolygonException::class); + + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(0, 0)); + $polygon->addPoint(new Coordinate(10, 10)); + + $this->formatter->format($polygon); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polyline/GeoJSONTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polyline/GeoJSONTest.php new file mode 100644 index 000000000..f6c491562 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Formatter/Polyline/GeoJSONTest.php @@ -0,0 +1,46 @@ +formatter = new GeoJSON(); + } + + /** + * Tears down the fixture, for example, closes a network connection. + * This method is called after a test is executed. + */ + protected function tearDown(): void + { + unset($this->formatter); + } + + public function testFormatDefault(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(52.5, 13.5)); + $polyline->addPoint(new Coordinate(62.5, 14.5)); + + $json = '{ "type" : "LineString" , "coordinates" : [ [ 13.5, 52.5 ], [ 14.5, 62.5 ] ] }'; + + $this->assertJsonStringEqualsJsonString($json, $this->formatter->format($polyline)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Intersection/IntersectionTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Intersection/IntersectionTest.php new file mode 100644 index 000000000..4f930a3a6 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Intersection/IntersectionTest.php @@ -0,0 +1,210 @@ +polygon = new Polygon(); + foreach ($coordinates as $coordinate) { + $this->polygon->addPoint(new Coordinate($coordinate[0], $coordinate[1])); + } + } + + public function testLineIntersections(): void + { + // Lines + $lineCenterCrossing = new Line( + new Coordinate(52.237594, 9.287635), + new Coordinate(52.258154, 11.010313) + ); + $lineTop = new Line( + new Coordinate(52.62456, 9.455537), + new Coordinate(52.608249, 10.734953) + ); + $lineBottom = new Line( + new Coordinate(51.880405, 9.613366), + new Coordinate(51.907345, 10.724879) + ); + $lineRight = new Line( + new Coordinate(52.720262, 10.627496), + new Coordinate(51.859671, 10.812188) + ); + + $intersection = new Intersection(); + + // By bounds + $this->assertTrue( + $intersection->intersects($lineCenterCrossing, $this->polygon, false) + ); + $this->assertFalse($intersection->intersects($lineTop, $this->polygon, false)); + $this->assertFalse($intersection->intersects($lineBottom, $this->polygon, false)); + $this->assertTrue($intersection->intersects($lineRight, $this->polygon, false)); + + // By shape + $this->assertTrue( + $intersection->intersects($lineCenterCrossing, $this->polygon, true) + ); + $this->assertFalse($intersection->intersects($lineTop, $this->polygon, true)); + $this->assertFalse($intersection->intersects($lineBottom, $this->polygon, true)); + $this->assertFalse($intersection->intersects($lineRight, $this->polygon, true)); + } + + public function testCoordinateIntersections(): void + { + $intersection = new Intersection(); + + // Coordinates + $pointContained = new Coordinate(52.328745, 10.151638); + $pointOutside = new Coordinate(52.549057, 10.475242); + $pointOutsideLine = new Coordinate(52.252717, 10.728334); + + // By bounds + $this->assertTrue($intersection->intersects($pointContained, $this->polygon, false)); + $this->assertFalse($intersection->intersects($pointOutside, $this->polygon, false)); + $this->assertFalse( + $intersection->intersects($pointOutsideLine, $this->polygon, false) + ); + + // By shape + $this->assertTrue($intersection->intersects($pointContained, $this->polygon, true)); + $this->assertFalse($intersection->intersects($pointOutside, $this->polygon, true)); + $this->assertFalse($intersection->intersects($pointOutsideLine, $this->polygon, true)); + } + + public function testPolygonIntersections(): void + { + $intersection = new Intersection(); + + // Polygons + $polygonLeftIntersecting = new Polygon(); + $coordinates = [ + [51.990136, 9.438747], + [52.493904, 9.408525], + [52.518432, 9.77791], + [51.807794, 9.871935], + [51.809766, 9.886408], + [51.990136, 9.438747], + ]; + foreach ($coordinates as $coordinate) { + $polygonLeftIntersecting->addPoint( + new Coordinate($coordinate[0], $coordinate[1]) + ); + } + + $polygonRightOutside = new Polygon(); + $coordinates = [ + [52.533043, 10.747941], + [52.326314, 10.787294], + [52.317063, 11.117259], + [52.317063, 11.117259], + [52.533043, 10.747941], + ]; + foreach ($coordinates as $coordinate) { + $polygonRightOutside->addPoint( + new Coordinate($coordinate[0], $coordinate[1]) + ); + } + + // By bounds + $this->assertTrue( + $intersection->intersects($polygonLeftIntersecting, $this->polygon, false) + ); + $this->assertFalse( + $intersection->intersects($polygonRightOutside, $this->polygon, false) + ); + + // By shape + $this->assertTrue( + $intersection->intersects($polygonLeftIntersecting, $this->polygon, true) + ); + $this->assertFalse( + $intersection->intersects($polygonRightOutside, $this->polygon, true) + ); + } + + public function testPolylineIntersections(): void + { + $intersection = new Intersection(); + + $polyline1 = new Polyline(); + $polyline1->addPoint(new Coordinate(-4, -2)); + $polyline1->addPoint(new Coordinate(5, 2)); + $polyline1->addPoint(new Coordinate(-1, 7)); + $polyline1->addPoint(new Coordinate(-3, 4)); + + $polyline2 = new Polyline(); + $polyline2->addPoint(new Coordinate(-8, 3)); + $polyline2->addPoint(new Coordinate(-5, -5)); + $polyline2->addPoint(new Coordinate(4, -3)); + + $polyline4 = new Polyline(); + $polyline4->addPoint(new Coordinate(1, 10)); + $polyline4->addPoint(new Coordinate(-1, 5)); + $polyline4->addPoint(new Coordinate(-6, 9)); + + $polyline3 = new Polyline(); + $polyline3->addPoint(new Coordinate(11, 13)); + $polyline3->addPoint(new Coordinate(21, 14)); + $polyline3->addPoint(new Coordinate(15, 18)); + + $polyline5 = new Polyline(); + $polyline5->addPoint(new Coordinate(9, 22)); + $polyline5->addPoint(new Coordinate(13, 24)); + $polyline5->addPoint(new Coordinate(14, 20)); + $polyline5->addPoint(new Coordinate(8, 15)); + + // By bounds + $this->assertTrue($intersection->intersects($polyline3, $polyline5, false)); + $this->assertTrue($intersection->intersects($polyline5, $polyline3, false)); + + $this->assertFalse($intersection->intersects($polyline2, $polyline3, false)); + $this->assertFalse($intersection->intersects($polyline3, $polyline2, false)); + + $this->assertTrue($intersection->intersects($polyline1, $polyline2, false)); + $this->assertTrue($intersection->intersects($polyline2, $polyline1, false)); + + $this->assertTrue($intersection->intersects($polyline1, $polyline4, false)); + $this->assertTrue($intersection->intersects($polyline4, $polyline1, false)); + + // By shape + $this->assertTrue($intersection->intersects($polyline1, $polyline4, true)); + $this->assertTrue($intersection->intersects($polyline4, $polyline1, true)); + + $this->assertFalse($intersection->intersects($polyline1, $polyline3, true)); + $this->assertFalse($intersection->intersects($polyline3, $polyline1, true)); + + $this->assertFalse($intersection->intersects($polyline1, $polyline5, true)); + $this->assertFalse($intersection->intersects($polyline5, $polyline1, true)); + + $this->assertFalse($intersection->intersects($polyline2, $polyline3, true)); + $this->assertFalse($intersection->intersects($polyline3, $polyline2, true)); + + $this->assertFalse($intersection->intersects($polyline2, $polyline4, true)); + $this->assertFalse($intersection->intersects($polyline4, $polyline2, true)); + + $this->assertFalse($intersection->intersects($polyline2, $polyline5, true)); + $this->assertFalse($intersection->intersects($polyline5, $polyline2, true)); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/LineTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/LineTest.php new file mode 100644 index 000000000..9872a39f8 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/LineTest.php @@ -0,0 +1,152 @@ +assertEquals($point1, $line->getPoint1()); + $this->assertEquals($point2, $line->getPoint2()); + } + + public function testCalculateLength(): void + { + $point1 = new Coordinate(52.5, 13.5); + $point2 = new Coordinate(64.1, -21.9); + + $line = new Line($point1, $point2); + + $this->assertEqualsWithDelta(2397867.8, $line->getLength(new Vincenty()), 0.01, ''); + } + + public function testGetReverseWorksAsExpected(): void + { + $point1 = new Coordinate(52.5, 13.5); + $point2 = new Coordinate(64.1, -21.9); + + $line = new Line($point1, $point2); + $reversedLine = $line->getReverse(); + + $expected = new Line($point2, $point1); + + $this->assertEquals($expected, $reversedLine); + } + + public function testIfGetBearingWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $line = new Line($point1, $point2); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(90.0, $line->getBearing($bearingCalculator)); + } + + public function testIfGetFinalBearingWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $line = new Line($point1, $point2); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(90.0, $line->getFinalBearing($bearingCalculator)); + } + + public function testIfGetBearingReversedWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $line = new Line($point2, $point1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(270.0, $line->getBearing($bearingCalculator)); + } + + public function testIfGetFinalBearingReversedWorksAsExpected(): void + { + $point1 = new Coordinate(0, 0); + $point2 = new Coordinate(0, 10); + + $line = new Line($point2, $point1); + + $bearingCalculator = new BearingEllipsoidal(); + + $this->assertEquals(270.0, $line->getFinalBearing($bearingCalculator)); + } + + public function testIfGetBoundsWorksAsExpected(): void + { + $point1 = new Coordinate(-10.0, 20.0); + $point2 = new Coordinate(3.0, 10.0); + + $line = new Line($point2, $point1); + + $expected = new Bounds(new Coordinate(3.0, 10.0), new Coordinate(-10.0, 20.0)); + + $this->assertEquals($expected, $line->getBounds()); + } + + public function testIfGetMidpointWorksAsExpected() + { + $line = new Line(new Coordinate(0, 0), new Coordinate(10, 20)); + + $this->assertEqualsWithDelta(5.07672, $line->getMidpoint()->getLat(), 0.0001); + $this->assertEqualsWithDelta(9.92267, $line->getMidpoint()->getLng(), 0.0001); + + $line = new Line(new Coordinate(1, 1), new Coordinate(-2, -2)); + + $this->assertEqualsWithDelta(-0.5, $line->getMidpoint()->getLat(), 0.001); + $this->assertEqualsWithDelta(-0.5, $line->getMidpoint()->getLng(), 0.001); + + $line = new Line(new Coordinate(35, -90), new Coordinate(35.2, -90.4)); + + $this->assertEqualsWithDelta(35.1, $line->getMidpoint()->getLat(), 0.001); + $this->assertEqualsWithDelta(-90.2, $line->getMidpoint()->getLng(), 0.001); + } + + public function testIfGetMidpointAcrossLongitudeBorderWorksAsExpected() + { + $line = new Line(new Coordinate(0.0, -179.0), new Coordinate(0.0, 179.0)); + $this->assertEquals(new Coordinate(0.0, -180.0), $line->getMidpoint()); + + $line = new Line(new Coordinate(0.0, -178.0), new Coordinate(0.0, 179.0)); + $this->assertEquals(new Coordinate(0.0, -179.5), $line->getMidpoint()); + } + + public function testIfGetIntermediatePointWorksAsExpected() + { + $line = new Line(new Coordinate(0, 0), new Coordinate(0, 1)); + $this->assertEquals(new Coordinate(0, 0), $line->getIntermediatePoint(0.)); + $line = new Line(new Coordinate(0, 0), new Coordinate(0, 1)); + $this->assertEquals(new Coordinate(0, .5), $line->getIntermediatePoint(.5)); + $line = new Line(new Coordinate(0, 0), new Coordinate(0, 1)); + $this->assertEquals(new Coordinate(0, 1), $line->getIntermediatePoint(1.)); + } + + public function testIfGetIntermediatePointThrowsExceptionForAntipodes() + { + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(5382449689); + + $line = new Line(new Coordinate(45, -45), new Coordinate(-45, 135)); + $line->getIntermediatePoint(.5); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/PolygonTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/PolygonTest.php new file mode 100644 index 000000000..920d0bfb5 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/PolygonTest.php @@ -0,0 +1,569 @@ +assertEquals([], $polygon->getPoints()); + + $point1 = new Coordinate(10, 10); + $polygon->addPoint($point1); + + $this->assertEquals([$point1], $polygon->getPoints()); + + $point2 = new Coordinate(10, 20); + $polygon->addPoint($point2); + + $this->assertEquals([$point1, $point2], $polygon->getPoints()); + } + + public function testIfGetNumberOfPointsWorksAsExpected(): void + { + $polygon = new Polygon(); + + $this->assertEquals(0, $polygon->getNumberOfPoints()); + + $polygon->addPoint(new Coordinate(10, 10)); + + $this->assertEquals(1, $polygon->getNumberOfPoints()); + + $polygon->addPoint(new Coordinate(10, 20)); + + $this->assertEquals(2, $polygon->getNumberOfPoints()); + } + + public function testIfGetSegmentsWorksAsExpected(): void + { + $polygon = new Polygon(); + + $point1 = new Coordinate(10, 20); + $point2 = new Coordinate(10, 40); + $point3 = new Coordinate(30, 40); + $point4 = new Coordinate(30, 20); + $polygon->addPoint($point1); + $polygon->addPoint($point2); + $polygon->addPoint($point3); + $polygon->addPoint($point4); + + $expected = [ + new Line($point1, $point2), + new Line($point2, $point3), + new Line($point3, $point4), + new Line($point4, $point1), + ]; + + $this->assertEquals($expected, $polygon->getSegments()); + } + + public function testIfGetLatsWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(10, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $expected = [10, 10, 30, 30]; + + $this->assertEquals($expected, $polygon->getLats()); + } + + public function testIfGetLngsWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(10, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $expected = [20, 40, 40, 20]; + + $this->assertEquals($expected, $polygon->getLngs()); + } + + public function testIfContainsPointCheckWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(10, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $point = new Coordinate(20, 30); + + $this->assertTrue($polygon->contains($point)); + } + + public function testIfContainsPointCheckWithLatitudeSignSwitchWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(- 30, 20)); + $polygon->addPoint(new Coordinate(- 30, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $point = new Coordinate(0, 30); + $this->assertTrue($polygon->contains($point)); + + $point = new Coordinate(- 10, 30); + $this->assertTrue($polygon->contains($point)); + + $point = new Coordinate(10, 30); + $this->assertTrue($polygon->contains($point)); + } + + public function testIfContainsPointCheckWithLongitudeSignSwitchWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, - 20)); + $polygon->addPoint(new Coordinate(10, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, - 20)); + + $point = new Coordinate(20, 0); + $this->assertTrue($polygon->contains($point)); + + $point = new Coordinate(20, - 10); + $this->assertTrue($polygon->contains($point)); + + $point = new Coordinate(20, 10); + $this->assertTrue($polygon->contains($point)); + } + + public function testIfNotContainsPointCheckWithWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(10, 40)); + $polygon->addPoint(new Coordinate(30, 40)); + $polygon->addPoint(new Coordinate(30, 20)); + + $point = new Coordinate(20, 10); + $this->assertFalse($polygon->contains($point)); + + $point = new Coordinate(20, 50); + $this->assertFalse($polygon->contains($point)); + + $point = new Coordinate(0, 30); + $this->assertFalse($polygon->contains($point)); + + $point = new Coordinate(40, 30); + $this->assertFalse($polygon->contains($point)); + } + + /* + public function testIfContainsPointCheckWithLongitudesCrossingThe180thMeridianWorksAsExpected() + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 150)); + $polygon->addPoint(new Coordinate(10, -150)); + $polygon->addPoint(new Coordinate(30, -150)); + $polygon->addPoint(new Coordinate(30, 150)); + + $point = new Coordinate(20, 160); + $this->assertTrue($polygon->contains($point)); + + $point = new Coordinate(20, -160); + $this->assertTrue($polygon->contains($point)); + } + */ + + public function testIfPerimeterCalculationWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(10, 10)); + $polygon->addPoint(new Coordinate(10, 20)); + $polygon->addPoint(new Coordinate(20, 20)); + $polygon->addPoint(new Coordinate(20, 10)); + + // http://geographiclib.sourceforge.net/cgi-bin/Planimeter?type=polygon&rhumb=geodesic&input=10+10%0D%0A10+20%0D%0A20+20%0D%0A20+10&norm=decdegrees&option=Submit + $this->assertEqualsWithDelta(4355689.472548, $polygon->getPerimeter(new Vincenty()), 0.01, ''); + + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52, 13)); + $polygon->addPoint(new Coordinate(53, 13)); + $polygon->addPoint(new Coordinate(53, 12)); + $polygon->addPoint(new Coordinate(52, 12)); + + // http://geographiclib.sourceforge.net/cgi-bin/Planimeter?type=polygon&rhumb=geodesic&input=52+13%0D%0A53+13%0D%0A53+12%0D%0A52+12&norm=decdegrees&option=Submit + $this->assertEqualsWithDelta(358367.809428, $polygon->getPerimeter(new Vincenty()), 0.01, ''); + } + + public function testIfAreaCalculationWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(0.0000000000, 0.0000000000)); + $polygon->addPoint(new Coordinate(0.0000000000, 0.0008983153)); + $polygon->addPoint(new Coordinate(0.0009043695, 0.0008983153)); + $polygon->addPoint(new Coordinate(0.0009043695, 0.0000000000)); + + // https://geographiclib.sourceforge.io/cgi-bin/Planimeter?type=polygon&rhumb=geodesic&input=0.0000000000+0.0000000000%0D%0A0.0000000000+0.0008983153%0D%0A0.0009043695+0.0008983153%0D%0A0.0009043695+0.0000000000&norm=decdegrees&option=Submit + //$this->assertEquals(10000.0, $polygon->getArea(), '', 1.0); + } + + public function testIfPolygonContainsGeometryWithPolygonInsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $insidePolygon = new Polygon(); + $insidePolygon->addPoint(new Coordinate(52.206110581755638, 13.674710914492607)); + $insidePolygon->addPoint(new Coordinate(52.202216433361173, 13.673997698351741)); + $insidePolygon->addPoint(new Coordinate(52.20279042609036, 13.666518358513713)); + $insidePolygon->addPoint(new Coordinate(52.209159163758159, 13.667042898014188)); + $insidePolygon->addPoint(new Coordinate(52.215381134301424, 13.664670567959547)); + $insidePolygon->addPoint(new Coordinate(52.209875900298357, 13.672981224954128)); + + $this->assertTrue($polygon->containsGeometry($insidePolygon)); + } + + public function testIfPolygonContainsGeometryWithPolygonInsideAndOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $inAndOutSidePolygon = new Polygon(); + $inAndOutSidePolygon->addPoint(new Coordinate(52.206110581755638, 13.674710914492607)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.202216433361173, 13.673997698351741)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.20279042609036, 13.666518358513713)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.209159163758159, 13.667042898014188)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.215381134301424, 13.664670567959547)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.209875900298357, 13.672981224954128)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.211303086951375, 13.676270367577672)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.20556978136301, 13.688599476590753)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.205583276227117, 13.688599476590753)); + $inAndOutSidePolygon->addPoint(new Coordinate(52.204232113435864, 13.683774350211024)); + + $this->assertFalse($polygon->containsGeometry($inAndOutSidePolygon)); + } + + public function testIfPolygonContainsGeometryWithPolygonOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $outsidePolygon = new Polygon(); + $outsidePolygon->addPoint(new Coordinate(52.2123983502388, 13.677485324442387)); + $outsidePolygon->addPoint(new Coordinate(52.215186841785908, 13.683912232518196)); + $outsidePolygon->addPoint(new Coordinate(52.207024795934558, 13.685344364494085)); + + $this->assertFalse($polygon->containsGeometry($outsidePolygon)); + } + + public function testIfPolygonContainsGeometryWithPolylineInsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $insidePolyline = new Polyline(); + $insidePolyline->addPoint(new Coordinate(52.206110581755638, 13.674710914492607)); + $insidePolyline->addPoint(new Coordinate(52.202216433361173, 13.673997698351741)); + $insidePolyline->addPoint(new Coordinate(52.20279042609036, 13.666518358513713)); + $insidePolyline->addPoint(new Coordinate(52.209159163758159, 13.667042898014188)); + $insidePolyline->addPoint(new Coordinate(52.215381134301424, 13.664670567959547)); + $insidePolyline->addPoint(new Coordinate(52.209875900298357, 13.672981224954128)); + + $this->assertTrue($polygon->containsGeometry($insidePolyline)); + } + + public function testIfPolygonContainsGeometryWithPolylineInsideAndOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $inAndOutSidePolyline = new Polyline(); + $inAndOutSidePolyline->addPoint(new Coordinate(52.206110581755638, 13.674710914492607)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.202216433361173, 13.673997698351741)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.20279042609036, 13.666518358513713)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.209159163758159, 13.667042898014188)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.215381134301424, 13.664670567959547)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.209875900298357, 13.672981224954128)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.211303086951375, 13.676270367577672)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.20556978136301, 13.688599476590753)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.205583276227117, 13.688599476590753)); + $inAndOutSidePolyline->addPoint(new Coordinate(52.204232113435864, 13.683774350211024)); + + $this->assertFalse($polygon->containsGeometry($inAndOutSidePolyline)); + } + + public function testIfPolygonContainsGeometryWithPolylineOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $outsidePolyline = new Polyline(); + $outsidePolyline->addPoint(new Coordinate(52.2123983502388, 13.677485324442387)); + $outsidePolyline->addPoint(new Coordinate(52.215186841785908, 13.683912232518196)); + $outsidePolyline->addPoint(new Coordinate(52.207024795934558, 13.685344364494085)); + + $this->assertFalse($polygon->containsGeometry($outsidePolyline)); + } + + public function testIfPolygonContainsGeometryWithLineInsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $insideLine = new Line( + new Coordinate(52.206110581755638, 13.674710914492607), + new Coordinate(52.202216433361173, 13.673997698351741) + ); + + $this->assertTrue($polygon->containsGeometry($insideLine)); + } + + public function testIfPolygonContainsGeometryWithLineInsideAndOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $inAndOutSidePolyline = new Line( + new Coordinate(52.207389576360583, 13.670525830239058), + new Coordinate(52.210680730640888, 13.687128368765116) + ); + + $this->assertFalse($polygon->containsGeometry($inAndOutSidePolyline)); + } + + public function testIfPolygonContainsGeometryWithLineOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $outsidePolyline = new Line( + new Coordinate(52.215186841785908, 13.683912232518196), + new Coordinate(52.207024795934558, 13.685344364494085) + ); + + $this->assertFalse($polygon->containsGeometry($outsidePolyline)); + } + + public function testIfPolygonContainsGeometryWithPointInsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $this->assertTrue($polygon->containsGeometry(new Coordinate(52.206110581755638, 13.674710914492607))); + } + + public function testIfPolygonContainsGeometryWithPointOutsideWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.221651719883084, 13.661613101139665)); + $polygon->addPoint(new Coordinate(52.215716242790222, 13.662988655269146)); + $polygon->addPoint(new Coordinate(52.211922844871879, 13.662990247830749)); + $polygon->addPoint(new Coordinate(52.208002796396613, 13.664533020928502)); + $polygon->addPoint(new Coordinate(52.203469779342413, 13.664621533825994)); + $polygon->addPoint(new Coordinate(52.199896154925227, 13.665583860129118)); + $polygon->addPoint(new Coordinate(52.199177406728268, 13.665664242580533)); + $polygon->addPoint(new Coordinate(52.197426510974765, 13.664221465587616)); + $polygon->addPoint(new Coordinate(52.196468207985163, 13.674150248989463)); + $polygon->addPoint(new Coordinate(52.200047867372632, 13.674412602558732)); + $polygon->addPoint(new Coordinate(52.203508755192161, 13.676183195784688)); + $polygon->addPoint(new Coordinate(52.206863863393664, 13.678688379004598)); + $polygon->addPoint(new Coordinate(52.213457236066461, 13.67043505422771)); + $polygon->addPoint(new Coordinate(52.217430174350739, 13.66775787435472)); + $polygon->addPoint(new Coordinate(52.221683654934168, 13.661622740328312)); + + $this->assertFalse($polygon->containsGeometry(new Coordinate(52.2123983502388, 13.677485324442387))); + } + + public function testGetReverseWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.5, 13.5)); + $polygon->addPoint(new Coordinate(64.1, - 21.9)); + $polygon->addPoint(new Coordinate(40.7, - 74.0)); + $polygon->addPoint(new Coordinate(33.9, - 118.4)); + + $reversed = $polygon->getReverse(); + + $expected = new Polygon(); + $expected->addPoint(new Coordinate(33.9, - 118.4)); + $expected->addPoint(new Coordinate(40.7, - 74.0)); + $expected->addPoint(new Coordinate(64.1, - 21.9)); + $expected->addPoint(new Coordinate(52.5, 13.5)); + + $this->assertEquals($expected, $reversed); + } + + public function testReverseTwiceWorksAsExpected(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.5, 13.5)); + $polygon->addPoint(new Coordinate(64.1, - 21.9)); + $polygon->addPoint(new Coordinate(40.7, - 74.0)); + $polygon->addPoint(new Coordinate(33.9, - 118.4)); + + $doubleReversed = $polygon->getReverse()->getReverse(); + + $this->assertEquals($polygon, $doubleReversed); + } + + public function testIfGetBoundsWorksAsExpected(): void + { + $polygon = new Polygon(); + + $point1 = new Coordinate(10.0, -20.0); + $point2 = new Coordinate(-10.0, 40.0); + $point3 = new Coordinate(30.0, 50.0); + $point4 = new Coordinate(40.0, 20.0); + $polygon->addPoint($point1); + $polygon->addPoint($point2); + $polygon->addPoint($point3); + $polygon->addPoint($point4); + + $expected = new Bounds(new Coordinate(40.0, -20.0), new Coordinate(-10.0, 50.0)); + + $this->assertEquals($expected, $polygon->getBounds()); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/PolylineTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/PolylineTest.php new file mode 100644 index 000000000..3ae46938d --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/PolylineTest.php @@ -0,0 +1,159 @@ +polyline = new Polyline(); + $this->polyline->addPoint(new Coordinate(52.5, 13.5)); + $this->polyline->addPoint(new Coordinate(64.1, -21.9)); + $this->polyline->addPoint(new Coordinate(40.7, -74.0)); + $this->polyline->addPoint(new Coordinate(33.9, -118.4)); + } + + public function testCreatePolyline(): void + { + static::assertCount(4, $this->polyline->getPoints()); + } + + public function testGetSegments(): void + { + $segments = $this->polyline->getSegments(); + + static::assertEquals(new Line(new Coordinate(52.5, 13.5), new Coordinate(64.1, -21.9)), $segments[0]); + static::assertEquals(new Line(new Coordinate(64.1, -21.9), new Coordinate(40.7, -74.0)), $segments[1]); + static::assertEquals(new Line(new Coordinate(40.7, -74.0), new Coordinate(33.9, -118.4)), $segments[2]); + } + + public function testGetSegmentsForOnlyOnePointInLineWorksAsExpected(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(52.5, 13.5)); + + static::assertEquals([], $polyline->getSegments()); + } + + public function testGetLength(): void + { + static::assertEqualsWithDelta(10576798.9, $this->polyline->getLength(new Vincenty()), 0.1, ''); + } + + public function testGetReverseWorksAsExpected(): void + { + $reversed = $this->polyline->getReverse(); + + $expected = new Polyline(); + $expected->addPoint(new Coordinate(33.9, -118.4)); + $expected->addPoint(new Coordinate(40.7, -74.0)); + $expected->addPoint(new Coordinate(64.1, -21.9)); + $expected->addPoint(new Coordinate(52.5, 13.5)); + + static::assertEquals($expected, $reversed); + } + + public function testReverseTwiceWorksAsExpected(): void + { + $doubleReversed = $this->polyline->getReverse()->getReverse(); + + static::assertEquals($this->polyline, $doubleReversed); + } + + public function testGetBoundsWorksAsExpected(): void + { + $expected = new Bounds(new Coordinate(64.1, -118.4), new Coordinate(33.9, 13.5)); + + static::assertEquals($expected, $this->polyline->getBounds()); + } + + public function testAddUniquePointWorksAsExpeted(): void + { + $expected = $this->polyline; + $unique = new Polyline(); + + // Pass 1 + $unique->addUniquePoint(new Coordinate(52.5, 13.5)); + $unique->addUniquePoint(new Coordinate(64.1, -21.9)); + $unique->addUniquePoint(new Coordinate(40.7, -74.0)); + $unique->addUniquePoint(new Coordinate(33.9, -118.4)); + + // Pass 2 + $unique->addUniquePoint(new Coordinate(52.5, 13.5)); + $unique->addUniquePoint(new Coordinate(64.1, -21.9)); + $unique->addUniquePoint(new Coordinate(40.7, -74.0)); + $unique->addUniquePoint(new Coordinate(33.9, -118.4)); + + static::assertEquals($unique, $expected); + } + + public function testAddUniquePointWithAllowedDistanceZero(): void + { + $expected = $this->polyline; + $actual = clone $expected; + + $actual->addUniquePoint(new Coordinate(33.9, -118.4), .0); + + static::assertEquals($expected, $actual); + + $expected->addPoint(new Coordinate(33.90001, -118.40001)); + $actual->addUniquePoint(new Coordinate(33.90001, -118.40001), .0); + + static::assertEquals($expected, $actual); + } + + public function testAddUniquePointWithAllowedDistance(): void + { + $expected = $this->polyline; + $actual = clone $expected; + + $actual->addUniquePoint(new Coordinate(33.90000001, -118.40000001), .001); + + static::assertEquals($expected, $actual); + + $expected = $this->polyline; + $actual = clone $expected; + + $actual->addUniquePoint(new Coordinate(33.900001, -118.400001), 1); + + static::assertEquals($expected, $actual); + } + + public function testGetAveragePointWorksAsExpected(): void + { + $middle = $this->polyline->getAveragePoint(); + + $this->assertEquals($middle, new Coordinate(47.8, -50.2)); + } + + public function testGetAveragePointCrossingDateLine(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(80.0, 179.0)); + $polyline->addPoint(new Coordinate(80.0, -179.0)); + + static::markTestSkipped('Polyline crossing dateline'); + } + + public function testGetAveragePointWithNoPoints(): void + { + $polyline = new Polyline(); + + $this->expectException(InvalidGeometryException::class); + $this->expectExceptionMessage('Polyline doesn\'t contain points'); + $this->expectExceptionCode(9464188927); + + $middle = $polyline->getAveragePoint(); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyBearingTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyBearingTest.php new file mode 100644 index 000000000..140a6b940 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyBearingTest.php @@ -0,0 +1,93 @@ +addPoint(new Coordinate(10.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 20.0)); + $polyline->addPoint(new Coordinate(30.0, 10.0)); + + $processor = new SimplifyBearing(85); + + // actual bearing difference between the both segments is + // 83.3 degrees, therefore the middle point gets removed + $simplified = $processor->simplify($polyline); + + $segments = $simplified->getSegments(); + + $this->assertEquals(1, count($segments)); + $this->assertEquals(new Line(new Coordinate(10.0, 10.0), new Coordinate(30.0, 10.0)), $segments[0]); + } + + public function testSimplifyTwoPointsImpossible(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(10.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 20.0)); + + $processor = new SimplifyBearing(10); + + $simplified = $processor->simplify($polyline); + + $this->assertEquals($polyline, $simplified); + } + + public function testSimplifyPolygon(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.22756274954098, 13.642145602718902)); + $polygon->addPoint(new Coordinate(52.239006313247366, 13.707722618459625)); + $polygon->addPoint(new Coordinate(52.24786291062496, 13.690119804191333)); + $polygon->addPoint(new Coordinate(52.25589445256298, 13.6807244463633)); + $polygon->addPoint(new Coordinate(52.259384204167624, 13.670769072927543)); + $polygon->addPoint(new Coordinate(52.263977114630265, 13.664195445135501)); + $polygon->addPoint(new Coordinate(52.2677055, 13.6518132)); + $polygon->addPoint(new Coordinate(52.2732257, 13.6453916)); + $polygon->addPoint(new Coordinate(52.27315767127478, 13.632664578662904)); + + $processor = new SimplifyBearing(45); + + $simplified = $processor->simplifyGeometry($polygon); + + $segments = $simplified->getSegments(); + + $this->assertCount(4, $segments); + $this->assertEquals( + new Line( + new Coordinate(52.22756274954098, 13.642145602718902), + new Coordinate(52.239006313247366, 13.707722618459625) + ), + $segments[0] + ); + $this->assertEquals( + new Line( + new Coordinate(52.239006313247366, 13.707722618459625), + new Coordinate(52.2732257, 13.6453916) + ), + $segments[1] + ); + $this->assertEquals( + new Line( + new Coordinate(52.2732257, 13.6453916), + new Coordinate(52.27315767127478, 13.632664578662904) + ), + $segments[2] + ); + $this->assertEquals( + new Line( + new Coordinate(52.27315767127478, 13.632664578662904), + new Coordinate(52.22756274954098, 13.642145602718902) + ), + $segments[3] + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyDouglasPeuckerTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyDouglasPeuckerTest.php new file mode 100644 index 000000000..1c9e3604a --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Processor/Polyline/SimplifyDouglasPeuckerTest.php @@ -0,0 +1,143 @@ +addPoint(new Coordinate(10.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 20.0)); + $polyline->addPoint(new Coordinate(30.0, 10.0)); + + $processor = new SimplifyDouglasPeucker(1500000); + + // actual deviation is 1046 km, so 1500 km is enough of tolerance to strip the 2nd coordinate + $simplified = $processor->simplify($polyline); + + $segments = $simplified->getSegments(); + + $this->assertCount(1, $segments); + $this->assertEquals(new Line(new Coordinate(10.0, 10.0), new Coordinate(30.0, 10.0)), $segments[0]); + } + + public function testSimplifyFourPointsToTwoPoints(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(50.0, 10.0)); + $polyline->addPoint(new Coordinate(40.0, 20.0)); + $polyline->addPoint(new Coordinate(30.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 30.0)); + + $processor = new SimplifyDouglasPeucker(1500000); + + $simplified = $processor->simplify($polyline); + + $segments = $simplified->getSegments(); + + $this->assertCount(1, $segments); + $this->assertEquals(new Line(new Coordinate(50.0, 10.0), new Coordinate(20.0, 30.0)), $segments[0]); + } + + public function testSimplifyFourPointsToThreePoints(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(50.0, 10.0)); + $polyline->addPoint(new Coordinate(40.0, 20.0)); + $polyline->addPoint(new Coordinate(30.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 30.0)); + + $processor = new SimplifyDouglasPeucker(1200000); + + $simplified = $processor->simplify($polyline); + + $segments = $simplified->getSegments(); + + $this->assertCount(2, $segments); + $this->assertEquals(new Line(new Coordinate(50.0, 10.0), new Coordinate(30.0, 10.0)), $segments[0]); + $this->assertEquals(new Line(new Coordinate(30.0, 10.0), new Coordinate(20.0, 30.0)), $segments[1]); + } + + public function testSimplifyThreePointsImpossible(): void + { + $polyline = new Polyline(); + $polyline->addPoint(new Coordinate(10.0, 10.0)); + $polyline->addPoint(new Coordinate(20.0, 20.0)); + $polyline->addPoint(new Coordinate(30.0, 10.0)); + + $processor = new SimplifyDouglasPeucker(1000); + + $simplified = $processor->simplify($polyline); + + $this->assertEquals($polyline, $simplified); + } + + public function testSimplifyPolygonFourPointsToThreePoints(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(50.0, 10.0)); + $polygon->addPoint(new Coordinate(40.0, 20.0)); + $polygon->addPoint(new Coordinate(30.0, 10.0)); + $polygon->addPoint(new Coordinate(20.0, 30.0)); + + $processor = new SimplifyDouglasPeucker(1200000); + + $simplified = $processor->simplifyGeometry($polygon); + + $segments = $simplified->getSegments(); + + $this->assertCount(3, $segments); + $this->assertEquals(new Line(new Coordinate(50.0, 10.0), new Coordinate(30.0, 10.0)), $segments[0]); + $this->assertEquals(new Line(new Coordinate(30.0, 10.0), new Coordinate(20.0, 30.0)), $segments[1]); + $this->assertEquals(new Line(new Coordinate(20.0, 30.0), new Coordinate(50.0, 10.0)), $segments[2]); + } + + public function testSimplifyPolygon(): void + { + $polygon = new Polygon(); + $polygon->addPoint(new Coordinate(52.22756274954098, 13.642145602718902)); + $polygon->addPoint(new Coordinate(52.239006313247366, 13.707722618459625)); + $polygon->addPoint(new Coordinate(52.24786291062496, 13.690119804191333)); + $polygon->addPoint(new Coordinate(52.25589445256298, 13.6807244463633)); + $polygon->addPoint(new Coordinate(52.259384204167624, 13.670769072927543)); + $polygon->addPoint(new Coordinate(52.263977114630265, 13.664195445135501)); + $polygon->addPoint(new Coordinate(52.2677055, 13.6518132)); + $polygon->addPoint(new Coordinate(52.2732257, 13.6453916)); + $polygon->addPoint(new Coordinate(52.27315767127478, 13.632664578662904)); + + $processor = new SimplifyDouglasPeucker(1000); + + $simplified = $processor->simplifyGeometry($polygon); + + $segments = $simplified->getSegments(); + + $this->assertCount(3, $segments); + $this->assertEquals( + new Line( + new Coordinate(52.22756274954098, 13.642145602718902), + new Coordinate(52.239006313247366, 13.707722618459625) + ), + $segments[0] + ); + $this->assertEquals( + new Line( + new Coordinate(52.239006313247366, 13.707722618459625), + new Coordinate(52.27315767127478, 13.632664578662904) + ), + $segments[1] + ); + $this->assertEquals( + new Line( + new Coordinate(52.27315767127478, 13.632664578662904), + new Coordinate(52.22756274954098, 13.642145602718902) + ), + $segments[2] + ); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/CartesianTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/CartesianTest.php new file mode 100644 index 000000000..5a4a2d91c --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/CartesianTest.php @@ -0,0 +1,39 @@ +point = new Cartesian(1.0, 2.0, 3.0); + } + + public function testGetX(): void + { + $this->assertEquals(1.0, $this->point->getX()); + } + + public function testGetZ(): void + { + $this->assertEquals(3.0, $this->point->getZ()); + } + + public function testGetY(): void + { + $this->assertEquals(2.0, $this->point->getY()); + } + + public function testAdd(): void + { + $expected = new Cartesian(4.0, 5.0, 6.0); + + $this->assertEquals($expected, $this->point->add(new Cartesian(3.0, 3.0, 3.0))); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestHaversineTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestHaversineTest.php new file mode 100644 index 000000000..56c604028 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestHaversineTest.php @@ -0,0 +1,157 @@ +haversine = new Haversine(); + $this->pointToLineDistance = new PointToLineDistance($this->haversine); + } + + public function testLineHasTheSameStartAndEndPoint(): void + { + $point = new Coordinate(52.5, 13.5); + + $line = new Line(new Coordinate(52.5, 13.1), new Coordinate(52.5, 13.1)); + + $this->assertEqualsWithDelta(27076, $this->pointToLineDistance->getDistance($point, $line), 1); + } + + public function testLinePoint1IsNearer(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals( + $point->getDistance($linePoint1, $this->haversine), + $this->pointToLineDistance->getDistance($point, $line) + ); + } + + public function testPointIsSameLocationAsLinePoint1(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.45, 13.05); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testLinePoint2IsNearer(): void + { + $point = new Coordinate(52.6001, 13.1201); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEqualsWithDelta( + $point->getDistance($linePoint2, $this->haversine), + $this->pointToLineDistance->getDistance($point, $line), + 0.001 + ); + } + + public function testPointIsSameLocationAsLinePoint2(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.45, 13.05); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testPointIsSameLocationAsLineMidPoint(): void + { + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $point = $line->getMidpoint(); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testDistanceIsCalculatedToSomewhereOnLine(): void + { + $point = new Coordinate(52.04, 13.01); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.07, 13.02); + $line = new Line($linePoint1, $linePoint2); + + $pl1Distance = $point->getDistance($linePoint1, $this->haversine); + $pl2Distance = $point->getDistance($linePoint2, $this->haversine); + $plDistance = $this->pointToLineDistance->getDistance($point, $line); + + $this->assertLessThan($pl1Distance, $plDistance); + $this->assertLessThan($pl2Distance, $plDistance); + } + + public function testDistanceMatchesPerpendicularDistance(): void + { + $point = new Coordinate(52.04, 13.01); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.07, 13.02); + $line = new Line($linePoint1, $linePoint2); + + $pdCalculator = new PerpendicularDistance(); + + $perpendicularDistance = $pdCalculator->getPerpendicularDistance($point, $line); + $pointToLineDistance = $this->pointToLineDistance->getDistance($point, $line); + + // allowed delta is relatively large because the perpdendicular distance + // is calculated with a simple spherical model + $this->assertEqualsWithDelta($pointToLineDistance, $perpendicularDistance, 0.3); + } + + public function testPointBetweenMidpointAndPoint2(): void + { + $point = new Coordinate(52.0419763, 13.3061232); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.1, 13.5); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEqualsWithDelta(2068, $this->pointToLineDistance->getDistance($point, $line), 1); + } + + public function testPointToLineDistanceCaseA() + { + $line = new Line(new Coordinate(55.9857757, 13.5475307), new Coordinate(55.9869533, 13.5509295)); + $point0a = new Coordinate(55.9839105, 13.5465958); + + $this->assertEqualsWithDelta(215, $point0a->getDistance($line->getPoint1(), $this->haversine), 1); + + $this->assertEqualsWithDelta(215, $this->pointToLineDistance->getDistance($point0a, $line), 1); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestVincentyTest.php b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestVincentyTest.php new file mode 100644 index 000000000..9c9833e37 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Location/Utility/PointToLineDistanceTestVincentyTest.php @@ -0,0 +1,158 @@ +vincenty = new Vincenty(); + $this->pointToLineDistance = new PointToLineDistance($this->vincenty); + } + + public function testLineHasTheSameStartAndEndPoint(): void + { + $point = new Coordinate(52.5, 13.5); + + $line = new Line(new Coordinate(52.5, 13.1), new Coordinate(52.5, 13.1)); + + $this->assertEquals(27164.059, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testLinePoint1IsNearer(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals( + $point->getDistance($linePoint1, $this->vincenty), + $this->pointToLineDistance->getDistance($point, $line) + ); + } + + public function testPointIsSameLocationAsLinePoint1(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.45, 13.05); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testLinePoint2IsNearer(): void + { + $point = new Coordinate(52.6001, 13.1201); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEqualsWithDelta( + $point->getDistance($linePoint2, $this->vincenty), + $this->pointToLineDistance->getDistance($point, $line), + 0.001 + ); + } + + public function testPointIsSameLocationAsLinePoint2(): void + { + $point = new Coordinate(52.45, 13.05); + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.45, 13.05); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testPointIsSameLocationAsLineMidPoint(): void + { + + $linePoint1 = new Coordinate(52.5, 13.1); + $linePoint2 = new Coordinate(52.6, 13.12); + $line = new Line($linePoint1, $linePoint2); + + $point = $line->getMidpoint(); + + $this->assertEquals(0, $this->pointToLineDistance->getDistance($point, $line)); + } + + public function testDistanceIsCalculatedToSomewhereOnLine(): void + { + $point = new Coordinate(52.04, 13.01); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.07, 13.02); + $line = new Line($linePoint1, $linePoint2); + + $pl1Distance = $point->getDistance($linePoint1, $this->vincenty); + $pl2Distance = $point->getDistance($linePoint2, $this->vincenty); + $plDistance = $this->pointToLineDistance->getDistance($point, $line); + + $this->assertLessThan($pl1Distance, $plDistance); + $this->assertLessThan($pl2Distance, $plDistance); + } + + public function testDistanceMatchesPerpendicularDistance(): void + { + $point = new Coordinate(52.04, 13.01); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.07, 13.02); + $line = new Line($linePoint1, $linePoint2); + + $pdCalculator = new PerpendicularDistance(); + + $perpendicularDistance = $pdCalculator->getPerpendicularDistance($point, $line); + $pointToLineDistance = $this->pointToLineDistance->getDistance($point, $line); + + // allowed delta is relatively large because the perpdendicular distance + // is calculated with a simple spherical model + $this->assertEqualsWithDelta($pointToLineDistance, $perpendicularDistance, 0.3); + } + + public function testPointBetweenMidpointAndPoint2(): void + { + $point = new Coordinate(52.0419763, 13.3061232); + + $linePoint1 = new Coordinate(52.0, 13.0); + $linePoint2 = new Coordinate(52.1, 13.5); + $line = new Line($linePoint1, $linePoint2); + + $this->assertEqualsWithDelta(2069.9, $this->pointToLineDistance->getDistance($point, $line), 0.1); + } + + public function testPointToLineDistanceCaseA() + { + $line = new Line(new Coordinate(55.9857757, 13.5475307), new Coordinate(55.9869533, 13.5509295)); + $point0a = new Coordinate(55.9839105, 13.5465958); + + $this->assertEqualsWithDelta(215.636, $point0a->getDistance($line->getPoint1(), $this->vincenty), 0.1); + + $this->assertEqualsWithDelta(215.636, $this->pointToLineDistance->getDistance($point0a, $line), 0.1); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/15/Issue15Test.php b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/15/Issue15Test.php new file mode 100644 index 000000000..4c00a4510 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/15/Issue15Test.php @@ -0,0 +1,94 @@ +addPoint(new Coordinate($point[0], $point[1])); + } + + $processor = new SimplifyDouglasPeucker(2); + $simplified = $processor->simplify($polyline); + + $firstPoint = new Coordinate(20.6579781231, -103.422906054); + $lastPoint = new Coordinate(20.6610790881, -103.421889792); + + $this->assertEquals($firstPoint, $simplified->getPoints()[0]); + $this->assertEquals($lastPoint, $simplified->getPoints()[$simplified->getNumberOfPoints() - 1]); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/18/Issue18Test.php b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/18/Issue18Test.php new file mode 100644 index 000000000..c8634e893 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/18/Issue18Test.php @@ -0,0 +1,23 @@ +getDistance( + new Coordinate(0, 0), + new Coordinate(0, 0.1) + ); + + $this->assertIsFloat($distance); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/42/Issue42Test.php b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/42/Issue42Test.php new file mode 100644 index 000000000..3bb845ac8 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/42/Issue42Test.php @@ -0,0 +1,23 @@ +getDistance( + new Coordinate(45.306833, 5.887717), + new Coordinate(45.306833, 5.887733) + ); + + $this->assertEquals(1.255, $distance); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/68/Issue68Test.php b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/68/Issue68Test.php new file mode 100644 index 000000000..e2d1b3361 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/68/Issue68Test.php @@ -0,0 +1,22 @@ +assertEqualsWithDelta($expectedLatitude, $coordinates->getLat(), 0.00001); + $this->assertEqualsWithDelta($expectedLongitude, $coordinates->getLng(), 0.00001); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/92/Issue92Test.php b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/92/Issue92Test.php new file mode 100644 index 000000000..6fed9cc14 --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/Regression/Github/92/Issue92Test.php @@ -0,0 +1,68 @@ + 55.98467000751469413444283418357372283935546875, + 'lon' => 13.544430000324179985682349069975316524505615234375, + ]; + $ll2 = [ + 'lat' => 55.98461833972562118333371472544968128204345703125, + 'lon' => 13.54429500218709137016048771329224109649658203125, + ]; + $p = [ + 'lat' => 55.97609299999999876717993174679577350616455078125, + 'lon' => 13.5475989999999999469082467840053141117095947265625, + ]; + + $pointToLineDistanceCalculator = new PointToLineDistance(new Vincenty()); + + $dist = $pointToLineDistanceCalculator->getDistance( + new Coordinate($p['lat'], $p['lon']), + new Line( + new Coordinate($ll1['lat'], $ll1['lon']), + new Coordinate($ll2['lat'], $ll2['lon']) + ) + ); + + $this->assertEqualsWithDelta(971.37, $dist, 0.01); + } + + public function testForIssue92RoundedValues(): void + { + $ll1 = [ + 'lat' => 55.98467, + 'lon' => 13.54443, + ]; + $ll2 = [ + 'lat' => 55.98461, + 'lon' => 13.54429, + ]; + $p = [ + 'lat' => 55.97609, + 'lon' => 13.54759, + ]; + + $pointToLineDistanceCalculator = new PointToLineDistance(new Vincenty()); + + $dist = $pointToLineDistanceCalculator->getDistance( + new Coordinate($p['lat'], $p['lon']), + new Line( + new Coordinate($ll1['lat'], $ll1['lon']), + new Coordinate($ll2['lat'], $ll2['lon']) + ) + ); + + $this->assertEqualsWithDelta(970.74, $dist, 0.01); + } +} diff --git a/admin/vendor/mjaschen/phpgeo/tests/bootstrap.php b/admin/vendor/mjaschen/phpgeo/tests/bootstrap.php new file mode 100644 index 000000000..cf564ec7d --- /dev/null +++ b/admin/vendor/mjaschen/phpgeo/tests/bootstrap.php @@ -0,0 +1,3 @@ +