From e4a4c7b7ecde79d72f44d9e078439544cd7a45d1 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Fri, 9 Nov 2018 09:36:13 +0100 Subject: [PATCH 1/5] Do polygon check with only one query So far, we did a nested approach with several MySQL queries. This new approach reduces the polyhood checks to one query and does everything else in code. Usually, this is considered to be faster. Some testing/comparison could be interesting in this case. Signed-off-by: Adrian Schmutzler --- index.php | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/index.php b/index.php index a910b09..863202d 100644 --- a/index.php +++ b/index.php @@ -21,44 +21,38 @@ if (isset($_GET['lat']) && $_GET['lat'] !== "" && isset($_GET['long']) && $_GET['long'] !== "" && is_numeric($_GET['lat']) && is_numeric($_GET['long'])) { $lat = $_GET['lat']; $lon = $_GET['long']; + $point = array($lon,$lat); // coordinates of router // Zuerst nach geojson hood pruefen $pointLocation = new pointLocation(); // First only retrieve list of polyids try { - $rc = db::getInstance()->prepare("SELECT DISTINCT polyid, hoodid FROM polyhood"); + $rc = db::getInstance()->prepare("SELECT polyid, hoodid, lat, lon FROM polyhood"); $rc->execute(); } catch (PDOException $e) { exit(showError(500, $e)); } - $allpoly = $rc->fetchAll(); // list of polyids - // Abfrage der Polygone ob eins passt - foreach($allpoly as $row) { - try { - $rs = db::getInstance()->prepare("SELECT lat, lon FROM polyhood WHERE polyid=:polyid"); - $rs->bindParam(':polyid', $row['polyid']); - $rs->execute(); - } catch (PDOException $e) { - exit(showError(500, $e)); - } - - // create array of polygons - $polygons = array(); // list of polygons (array(lng,lat)) for the current polyid - while ($polygeo = $rs->fetch(PDO::FETCH_ASSOC)) { - debug('lon: '.$polygeo["lon"].' lat: '.$polygeo["lat"]); - array_push($polygons, array($polygeo["lon"],$polygeo["lat"])); + // Write polygon data into array + $polystore = array(); + while($row = $rc->fetch(PDO::FETCH_ASSOC)) { + if(!isset($polystore[$row['polyid'])) { + $polystore[$row['polyid']] = array('hoodid'=>$row['hoodid'],'data'=>array()); } + $polystore[$row['polyid']]['data'][] = array($row["lon"],$row["lat"]); + debug('lon: '.$row["lon"].' lat: '.$row["lat"]); + } - $point = array($lon,$lat); // coordinates of router - $inside = $pointLocation->pointInPolygon($point, $polygons); - debug("point $lon $lat: " . $inside . "
"); + // Interpret polygon data + foreach($polystore as $polyid => $polygon) { + $inside = $pointLocation->pointInPolygon($point, $polygon['data']); + debug("point in polygon #" . $polyid. ": " . $inside . "
"); if ($inside) { debug("PolyHood gefunden..."); try { $rs = db::getInstance()->prepare("SELECT ".hood_mysql_fields." FROM hoods WHERE id=:hoodid;"); - $rs->bindParam(':hoodid', $row['hoodid'], PDO::PARAM_INT); + $rs->bindParam(':hoodid', $polygon['hoodid'], PDO::PARAM_INT); $rs->execute(); } catch (PDOException $e) { exit(showError(500, $e)); From 4f254b5f9e19b55d5de8d9063685d4bc8211eaf8 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Fri, 9 Nov 2018 13:12:49 +0100 Subject: [PATCH 2/5] Put hood-to-polygon assignment in separate table The current design of the polyhood table includes the hoodid in every line. This is can (and should) be improved by creating a separate table for the hood-to-polygon assignment. The old table is renamed to "polygons" and only contains coordinates and polyid. Signed-off-by: Adrian Schmutzler --- database.sql | 66 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/database.sql b/database.sql index 62b73c6..f602764 100644 --- a/database.sql +++ b/database.sql @@ -98,32 +98,50 @@ INSERT INTO `hoods` (`ID`, `name`, `net`, `lat`, `lon`, `prefix`, `ntp_ip`, `ESS -- Table structure for table `polyhood` -- -CREATE TABLE `polyhood` ( +CREATE TABLE `polyhoods` ( + `polyid` int(10) unsigned NOT NULL, + `hoodid` int(10) unsigned NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `polyhoods` +-- + +INSERT INTO `polyhoods` (`polyid`, `hoodid`) VALUES +(1, 31), +(2, 32); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `polygons` +-- + +CREATE TABLE `polygons` ( `ID` int(10) unsigned NOT NULL, `polyid` int(10) unsigned NOT NULL, `lat` double NOT NULL, - `lon` double NOT NULL, - `hoodid` int(10) unsigned NOT NULL + `lon` double NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Dumping data for table `polyhood` -- -INSERT INTO `polyhood` (`ID`, `polyid`, `lat`, `lon`, `hoodid`) VALUES -(18, 1, 49.58982152, 10.99503994, 31), -(19, 1, 49.58940422, 11.01199150, 31), -(20, 1, 49.59685950, 11.01787090, 31), -(21, 1, 49.60270052, 11.01722717, 31), -(22, 1, 49.60712255, 10.99988937, 31), -(23, 1, 49.58982152, 10.99503994, 31), -(24, 2, 49.46979740, 11.01302147, 32), -(25, 2, 49.47983623, 10.99259377, 32), -(26, 2, 49.48569126, 10.98083496, 32), -(27, 2, 49.45546063, 10.97740173, 32), -(28, 2, 49.44798376, 10.99851608, 32), -(29, 2, 49.45395418, 11.00915909, 32), -(30, 2, 49.46979740, 11.01302147, 32); +INSERT INTO `polygons` (`ID`, `polyid`, `lat`, `lon`) VALUES +(18, 1, 49.58982152, 10.99503994), +(19, 1, 49.58940422, 11.01199150), +(20, 1, 49.59685950, 11.01787090), +(21, 1, 49.60270052, 11.01722717), +(22, 1, 49.60712255, 10.99988937), +(23, 1, 49.58982152, 10.99503994), +(24, 2, 49.46979740, 11.01302147), +(25, 2, 49.47983623, 10.99259377), +(26, 2, 49.48569126, 10.98083496), +(27, 2, 49.45546063, 10.97740173), +(28, 2, 49.44798376, 10.99851608), +(29, 2, 49.45395418, 11.00915909), +(30, 2, 49.46979740, 11.01302147); -- -- Indexes for dumped tables @@ -143,9 +161,15 @@ ALTER TABLE `hoods` ADD PRIMARY KEY (`ID`); -- --- Indexes for table `polyhood` +-- Indexes for table `polyhoods` -- -ALTER TABLE `polyhood` +ALTER TABLE `polyhoods` + ADD PRIMARY KEY (`polyid`); + +-- +-- Indexes for table `polygons` +-- +ALTER TABLE `polygons` ADD PRIMARY KEY (`ID`), ADD KEY `polyid` (`polyid`); @@ -161,8 +185,8 @@ ALTER TABLE `gateways` -- -- AUTO_INCREMENT for table `polyhood` -- -ALTER TABLE `polyhood` - MODIFY `id` int(10) unsigned NOT NULL AUTO_INCREMENT; +ALTER TABLE `polygons` + MODIFY `ID` int(10) unsigned NOT NULL AUTO_INCREMENT; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; From 30de835fde2d10e14d98b979c3bf8e13214e8824 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Fri, 9 Nov 2018 13:54:03 +0100 Subject: [PATCH 3/5] Fix database.sql Signed-off-by: Adrian Schmutzler --- database.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database.sql b/database.sql index f602764..5fa81e4 100644 --- a/database.sql +++ b/database.sql @@ -49,7 +49,7 @@ INSERT INTO `gateways` (`ID`, `name`, `publickey`, `ip`, `port`, `hood_ID`, `tim (9, 'vm3fffgwcd1', '373cf6dca701a8b1516b816a13c91dc9df29ac5a822d12331b503982d655399b', '144.76.70.186', 10005, 30, '2017-09-27 07:15:09'), (46, 'fff-neptun', '3834e45fa33c048f975e81042c1e93bb11dac82d9f03a0b24071bb72205247a8', '84.23.95.3', 10011, 31, '2018-09-02 09:00:59'), (47, 'fff-neptun', '3834e45fa33c048f975e81042c1e93bb11dac82d9f03a0b24071bb72205247a8', '84.23.95.3', 10012, 0, '2018-09-02 14:36:14'), -(49, 'fff-neptun', '3834e45fa33c048f975e81042c1e93bb11dac82d9f03a0b24071bb72205247a8', '84.23.95.3', 10013, 1, '2018-09-02 14:36:14'), +(49, 'fff-neptun', '3834e45fa33c048f975e81042c1e93bb11dac82d9f03a0b24071bb72205247a8', '84.23.95.3', 10013, 1, '2018-09-02 14:36:14'); -- -------------------------------------------------------- From d5f1ffd8618b1844c238dd18127f268bf6daaa06 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Fri, 9 Nov 2018 13:59:16 +0100 Subject: [PATCH 4/5] Implement two polyhood tables and add shortcut for extreme values This patch implements the two tables created in the previous patch. Exploiting the new structure, we can redesign the polyhood check to check whether the point is within a square defined by the extreme values of the coordinates, i.e. the latitude is smaller than the one of the southmost vertex etc. Although this is an extra check, it is much faster if we can skip a lot of full polygon checks. Since we expect mostly "normal" hoods and only few routers in polyhoods, this should be the case. Signed-off-by: Adrian Schmutzler --- function.php | 8 ++++++++ index.php | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/function.php b/function.php index 5166dad..deb0f62 100644 --- a/function.php +++ b/function.php @@ -24,6 +24,14 @@ class pointLocation { // Original version: https://gist.github.com/jeremejazz/5219848 // Modified by Adrian Schmutzler, 2018. + function excludePolygon($point, $minlon, $maxlon, $minlat, $maxlat) { + // exclude polygon if LAT/LNG of point is smaller than minimum lat/lng of all vertices + // or bigger than maximum ... + + // returning TRUE means exclusion, so polygon should NOT be used + return ($point[0] < $minlon or $point[0] > $maxlon or $point[1] < $minlat or $point[1] > $maxlat); + } + function pointInPolygon($point, $polygon, $pointOnVertex = true) { // Support both string version "lng lat" and array(lng,lat) diff --git a/index.php b/index.php index 863202d..5a81705 100644 --- a/index.php +++ b/index.php @@ -28,26 +28,52 @@ // First only retrieve list of polyids try { - $rc = db::getInstance()->prepare("SELECT polyid, hoodid, lat, lon FROM polyhood"); + $rc = db::getInstance()->prepare(" + SELECT polyhoods.polyid, hoodid, MIN(lat) AS minlat, MIN(lon) AS minlon, MAX(lat) AS maxlat, MAX(lon) AS maxlon + FROM polyhoods INNER JOIN polygons ON polyhoods.polyid = polygons.polyid + GROUP BY polyid, hoodid + "); // This query will automatically exclude polyhoods being present in polyhoods table, but without vertices in polygons table $rc->execute(); } catch (PDOException $e) { exit(showError(500, $e)); } - // Write polygon data into array + // Set up all polygons, but do it without vertex coordinates $polystore = array(); + while($row = $rc->fetch(PDO::FETCH_ASSOC)) { + $polystore[$row['polyid']] = $row; + $polystore[$row['polyid']]['data'] = array(); // prepare array for vertex coordinates + } + + // Now query the coordinates, all in one query + try { + $rc = db::getInstance()->prepare("SELECT polyid, lat, lon FROM polygons"); + $rc->execute(); + } catch (PDOException $e) { + exit(showError(500, $e)); + } + + // Write polygon coordinates into array while($row = $rc->fetch(PDO::FETCH_ASSOC)) { if(!isset($polystore[$row['polyid'])) { - $polystore[$row['polyid']] = array('hoodid'=>$row['hoodid'],'data'=>array()); + debug('Database inconsistent: No polyhood defined for ID '.$row['polyid']); + continue; // Skip those orphaned vertex entries } $polystore[$row['polyid']]['data'][] = array($row["lon"],$row["lat"]); debug('lon: '.$row["lon"].' lat: '.$row["lat"]); } // Interpret polygon data - foreach($polystore as $polyid => $polygon) { + foreach($polystore as $polygon) { + // First check whether point coordinates are outside the most extreme values for lat/lng + $exclude = $pointLocation->excludePolygon($point, $polygon['minlon'], $polygon['maxlon'], $polygon['minlat'], $polygon['maxlat']); + if ($exclude) { + debug("polygon #" . $polygon['polyid'] . " excluded
"); + continue; + } + // Now really check whether point is inside polygon $inside = $pointLocation->pointInPolygon($point, $polygon['data']); - debug("point in polygon #" . $polyid. ": " . $inside . "
"); + debug("point in polygon #" . $polygon['polyid'] . ": " . $inside . "
"); if ($inside) { debug("PolyHood gefunden..."); try { From 560b8bae29c854ef0b6d731b9cc78d0861c61bb6 Mon Sep 17 00:00:00 2001 From: Adrian Schmutzler Date: Fri, 9 Nov 2018 14:20:20 +0100 Subject: [PATCH 5/5] Fix typo (parsing error) Signed-off-by: Adrian Schmutzler --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.php b/index.php index 5a81705..113b9b5 100644 --- a/index.php +++ b/index.php @@ -55,7 +55,7 @@ // Write polygon coordinates into array while($row = $rc->fetch(PDO::FETCH_ASSOC)) { - if(!isset($polystore[$row['polyid'])) { + if(!isset($polystore[$row['polyid']])) { debug('Database inconsistent: No polyhood defined for ID '.$row['polyid']); continue; // Skip those orphaned vertex entries }