Resolve "Geofencing coverage area" #1032
6 changed files with 302 additions and 4 deletions
39
src/Command/ImportKMLFileCommand.php
Normal file
39
src/Command/ImportKMLFileCommand.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use App\Entity\SupportedArea;
|
||||
|
||||
use App\Service\KMLFileImporter;
|
||||
|
||||
class ImportKMLFileCommand extends Command
|
||||
{
|
||||
protected $importer;
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('supportedarea:import')
|
||||
->setDescription('Extracts map data of the supported area from the KML file and saves to database')
|
||||
->setHelp('Gets the coordinates of the supported area and saves to the database')
|
||||
->addArgument('file', InputArgument::REQUIRED, 'Path to the KML file');
|
||||
}
|
||||
|
||||
public function __construct(KMLFileImporter $importer)
|
||||
{
|
||||
$this->importer = $importer;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$kml_file = $input->getArgument('file');
|
||||
|
||||
$this->importer->getMapData($kml_file);
|
||||
}
|
||||
}
|
||||
44
src/Command/TestGeofenceCommand.php
Normal file
44
src/Command/TestGeofenceCommand.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
use App\Entity\SupportedArea;
|
||||
|
||||
use App\Service\GeofenceTracker;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
class TestGeofenceCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('test:geofence')
|
||||
->setDescription('Test geofence tracker service.')
|
||||
->setHelp('Test the geofence tracker service.')
|
||||
->addArgument('long', InputArgument::REQUIRED, 'Longitude')
|
||||
->addArgument('lat', InputArgument::REQUIRED, 'Latitude');
|
||||
}
|
||||
|
||||
public function __construct(GeofenceTracker $geo)
|
||||
{
|
||||
$this->geo = $geo;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$long = $input->getArgument('long');
|
||||
$lat = $input->getArgument('lat');
|
||||
|
||||
if ($this->geo->isCovered($long, $lat))
|
||||
echo "In geofence\n";
|
||||
else
|
||||
echo "NOT in geofence\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ use App\Ramcar\JOEventType;
|
|||
use App\Service\InvoiceCreator;
|
||||
use App\Service\RisingTideGateway;
|
||||
use App\Service\MQTTClient;
|
||||
use App\Service\GeofenceTracker;
|
||||
|
||||
use App\Entity\MobileSession;
|
||||
use App\Entity\Customer;
|
||||
|
|
@ -766,7 +767,7 @@ class APIController extends Controller
|
|||
return $res->getReturnResponse();
|
||||
}
|
||||
|
||||
public function requestJobOrder(Request $req, InvoiceCreator $ic)
|
||||
public function requestJobOrder(Request $req, InvoiceCreator $ic, GeofenceTracker $geo)
|
||||
{
|
||||
// check required parameters and api key
|
||||
$required_params = [
|
||||
|
|
@ -793,6 +794,19 @@ class APIController extends Controller
|
|||
// instructions
|
||||
$instructions = $req->request->get('delivery_instructions', '');
|
||||
|
||||
// longitude and latitude
|
||||
$long = $req->request->get('long');
|
||||
$lat = $req->request->get('lat');
|
||||
|
||||
// geofence
|
||||
$is_covered = $geo->isCovered($long, $lat);
|
||||
if (!$is_covered)
|
||||
{
|
||||
$res->setError(true)
|
||||
->setErrorMessage('Location is not covered by our service.');
|
||||
return $res->getReturnResponse();
|
||||
}
|
||||
|
||||
|
||||
$jo = new JobOrder();
|
||||
$jo->setSource(TransactionOrigin::MOBILE_APP)
|
||||
|
|
@ -836,9 +850,7 @@ class APIController extends Controller
|
|||
}
|
||||
$jo->setWarrantyClass($warr);
|
||||
|
||||
// longitude and latitude
|
||||
$long = $req->request->get('long');
|
||||
$lat = $req->request->get('lat');
|
||||
// set coordinates
|
||||
$point = new Point($long, $lat);
|
||||
$jo->setCoordinates($point);
|
||||
|
||||
|
|
|
|||
86
src/Entity/SupportedArea.php
Normal file
86
src/Entity/SupportedArea.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Polygon;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="supported_area")
|
||||
*/
|
||||
class SupportedArea
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// date supported area was created
|
||||
/**
|
||||
* @ORM\Column(type="datetime")
|
||||
*/
|
||||
protected $date_create;
|
||||
|
||||
// name of the supported area
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
// coordinates of the supported area
|
||||
/**
|
||||
* @ORM\Column(type="polygon")
|
||||
*/
|
||||
protected $coverage_area;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setDateCreate(DateTime $date_create)
|
||||
{
|
||||
$this->date_create = $date_create;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDateCreate()
|
||||
{
|
||||
return $this->date_Create;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setCoverageArea(Polygon $polygon)
|
||||
{
|
||||
$this->coverage_area = $polygon;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCoverageArea()
|
||||
{
|
||||
return $this->coverage_area;
|
||||
}
|
||||
}
|
||||
|
||||
35
src/Service/GeofenceTracker.php
Normal file
35
src/Service/GeofenceTracker.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\SupportedArea;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
class GeofenceTracker
|
||||
{
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function isCovered($long, $lat)
|
||||
{
|
||||
// see if the point is in any of the polygons
|
||||
$query = $this->em->createQuery('SELECT count(s) from App\Entity\SupportedArea s where st_contains(s.coverage_area, point(:long, :lat)) = true')
|
||||
->setParameter('long', $long)
|
||||
->setParameter('lat', $lat);
|
||||
|
||||
// number of polygons that contain the point
|
||||
$count = $query->getSingleScalarResult();
|
||||
|
||||
if ($count > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
82
src/Service/KMLFileImporter.php
Normal file
82
src/Service/KMLFileImporter.php
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use XMLReader;
|
||||
|
||||
use App\Entity\SupportedArea;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Polygon;
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\LineString;
|
||||
|
||||
class KMLFileImporter
|
||||
{
|
||||
protected $em;
|
||||
|
||||
public function __construct(EntityManagerInterface $em)
|
||||
{
|
||||
$this->em = $em;
|
||||
}
|
||||
|
||||
public function getMapData($fh)
|
||||
{
|
||||
$placemark_name = '';
|
||||
|
||||
$reader = new XMLReader();
|
||||
$reader->open($fh);
|
||||
|
||||
while($reader->read())
|
||||
{
|
||||
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == "Placemark")
|
||||
{
|
||||
while($reader->read())
|
||||
{
|
||||
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == "name")
|
||||
{
|
||||
$placemark_name = $reader->readInnerXML();
|
||||
}
|
||||
|
||||
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == "coordinates")
|
||||
{
|
||||
// each polygon is a new area
|
||||
$supported_area = new SupportedArea();
|
||||
$supported_area->setName($placemark_name);
|
||||
|
||||
$point_array = [];
|
||||
$coordinates = $reader->readInnerXML();
|
||||
|
||||
// get each line
|
||||
$coord_split = explode("\n", $coordinates);
|
||||
|
||||
// go through all the coordinates
|
||||
foreach ($coord_split as $coord)
|
||||
{
|
||||
// skip blank lines
|
||||
$coord_trim = trim($coord);
|
||||
if (strlen($coord_trim) <= 0)
|
||||
continue;
|
||||
|
||||
// echo "$coord_trim\n";
|
||||
|
||||
$point_split = explode(',', $coord_trim);
|
||||
|
||||
$point_array[] = new Point($point_split[0], $point_split[1]);
|
||||
}
|
||||
|
||||
$area = new Polygon([new LineString($point_array)]);
|
||||
$supported_area->setCoverageArea($area);
|
||||
|
||||
// add supported area
|
||||
$this->em->persist($supported_area);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$reader->close();
|
||||
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue