Merge branch '141-geofencing-coverage-area-2' into 'master'

Resolve "Geofencing coverage area"

Closes #141

See merge request jankstudio/resq!221
This commit is contained in:
Kendrick Chan 2019-03-10 17:34:17 +00:00
commit a1408c618c
6 changed files with 302 additions and 4 deletions

View 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);
}
}

View 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";
}
}

View file

@ -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);

View 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;
}
}

View 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;
}
}

View 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();
}
}