Prechádzať zdrojové kódy

Merge branch 'master' of bn.git:plabudda/se

Piotr Labudda 8 rokov pred
rodič
commit
06a7b8af3f

+ 2 - 3
SE/se-lib/EpsgConversion.php

@@ -102,7 +102,7 @@ class EpsgConversion {
 		} else {
 			$nfn = 0;
 			$strf = floor($lon / 1000000) * 1000000;
-			$olam = $strf / 1000000 * M_PI / 180;
+			$olam = $strf / 60000000 * M_PI;
 		}
 		$tmd = ($lat - $nfn) / $ok;
 		$sr = self::sphsr($a, $eSquared, 0);
@@ -124,13 +124,12 @@ class EpsgConversion {
         
 		$t12 = $t * (61 + 90 * pow($t, 2) + 46 * $eta + 45 * pow($t, 4) - 252 * pow($t, 2) * $eta - 3 * pow($eta, 2) + 100 * pow($eta, 3) - 66 * pow($t, 2) * pow($eta, 2) - 90 * pow($t, 4) * $eta + 88 * pow($eta, 4) + 225 * pow($t, 4) * pow($eta, 2) + 84 * pow($t, 2) * pow($eta, 3) - 192 * pow($t, 2) * pow($eta, 4)) / (720 * $sr * pow($sn, 5) * pow($ok, 6));
 		$t13 = $t * (1385 + 3633 * pow($t, 2) + 4095 * pow($t, 4) + 1575  * pow($t, 6)) / (40320 * $sr * pow($sn, 7) * pow($ok, 8));
-		$result->y = $ftphi - pow($de, 2) * $t10 + pow($de, 4) * $t11 - pow($de, 6) * $t12 + pow($de, 8) * $t13;
 		$t14 = 1 / ($sn * $c * $ok);
 		$t15 = (1 + 2 * pow($t, 2) + $eta) / (6 * pow($sn, 3) * $c * pow($ok, 3));
 		$t16 = 1 * (5 + 6 * $eta + 28 * pow($t, 2) - 3 * pow($eta, 2) + 8 * pow($t, 2) * $eta + 24 * pow($t, 4) - 4 * pow($eta, 3) + 4 * pow($t, 2) * pow($eta, 2) + 24 * pow($t, 2) * pow($eta, 3)) / (120 * pow($sn, 5) * $c * pow($ok, 5));
 		$t17 = 1 * (61 + 662 * pow($t, 2) + 1320 * pow($t, 4) + 720 * pow($t, 6)) / (5040 * pow($sn, 7) * $c * pow($ok, 7));
 		$dlam = $de * $t14 - pow($de, 3) * $t15 + pow($de, 5) * $t16 - pow($de, 7) * $t17;
-		$this->x = ($olam + $dlam) * 180 / M_PI;
+		$result->x = ($olam + $dlam) * 180 / M_PI;
 		$result->y = ($ftphi - pow($de, 2) * $t10 + pow($de, 4) * $t11 - pow($de, 6) * $t12 + pow($de, 8) * $t13) * 180 / M_PI;
 		return $result;
 	}

+ 269 - 23
SE/se-lib/Route/GeoreferencesManager.php

@@ -25,15 +25,24 @@ class Route_GeoreferencesManager extends RouteBase {
   <div class="form-group">
     <div class="col-sm-12">
       <a href="?_route=GeoreferencesManager&action=verifyPoints" class="btn-sm btn-primary">Zweryfikuj punkty</a>
+      <a href="?_route=GeoreferencesManager&action=uploadPoints" class="btn-sm btn-primary">Wgraj punkty</a><?=($this->ACTION ? "<hr/>" : "")?>
     </div>
-  </div>
+    <div class="col-sm-12">
 <?php
 		switch ($this->ACTION) {
 			case "verifyPoints":
 				$this->verifyPoints();
 				break;
+			case "repairPoints":
+				$this->repairPoints();
+				break;
+			case "uploadPoints":
+				$this->uploadPoints();
+				break;
 		}
 ?>
+    </div>
+  </div>
 </div>
 <?php
 		SE_Layout::dol();
@@ -47,43 +56,280 @@ class Route_GeoreferencesManager extends RouteBase {
 	public function reinstall() {
 	}
 
-	private function verifyPoints() {
+	private static function getBadPoints() {
 		$points = DB::getPDO()->fetchall("select `ID`, `EPSG`, x(`the_geom`) as `gx`, y(`the_geom`) as `gy`, `x`, `y` from `" . self::TABLE . "`");
 		$errors = [];
 		foreach ($points as $point) {
-			if ($point['x'] && $point['y']) {
-				if ($point['gx'] && $point['gy']) {
+			if ($point['x'] > 0 && $point['y'] > 0) {
+				if ($point['gx'] && $point['gy']) {	
 					try {
-						$test = epsgConversion::LatLonToPUWGWGS84($point['gx'], $point['gy']);
+						$test = epsgConversion::LonLatToPUWGWGS84($point['gx'], $point['gy']);
+						if (abs($point['x'] - $test->x) > 0.001) $errors["unfuckable"][$point["ID"]]["errors"][] = "x";
+						if (abs($point['y'] - $test->y) > 0.001) $errors["unfuckable"][$point["ID"]]["errors"][] = "y";
+						if ($point['EPSG'] != $test->epsg) $errors["unfuckable"][$point["ID"]]["errors"][] = "epsg";
+						if (isset($errors["unfuckable"][$point["ID"]])) $errors["unfuckable"][$point["ID"]]["data"] = $point;
 					} catch (Exception $e) {
-						SE_Layout::alert('danger', $e->getMessage());
+						$errors["nonunfuckable"][$point["ID"]]["data"] = $point;
 					}
-					if ((abs($point['x'] - $test->x) > 1 ) || (abs($point['y'] - $test->y) > 1) || ($point['EPSG'] != $test->epsg)) {
-						$error = "[{$point['ID']}] x = <span style='color:" . ((abs($point['x'] - $test->x) > 1) ? "red" : "green") .
-							";'>{$point['x']}</span> ({$test->x}), y = <span style='color:" . ((abs($point['y'] - $test->y) > 1) ? "red" : "green") .
-							";'>{$point['y']}</span> ({$test->y}), epsg = <span style='color:" . (($point['EPSG'] != $test->epsg) ? "red" : "green") .
-							";'>{$point['EPSG']}</span>" . (($point['EPSG'] != $test->epsg) ? " ({$test->epsg})" : "");
-						$errors[] = $error;
+				} else $errors["nonunfuckable"][$point["ID"]]["data"] = $point;
+			} elseif (!($point['gx'] && $point['gy'])) $errors["nonunfuckable"][$point["ID"]]["data"] = $point;
+		}
+		return $errors;
+	}
+
+	private function verifyPoints() {
+		$errorsData = self::getBadPoints();
+
+		if (isset($errorsData["unfuckable"])) {
+			$echo = '<b>Znalezione błędy, które można automatycznie naprawić:</b></br/><pre>';
+			foreach ($errorsData["unfuckable"] as $error) {
+				$ok = epsgConversion::PUWGToLonLatWGS84($error['data']['x'], $error['data']['y']);
+				$echo .= "[{$error['data']['ID']}] x = <span style='color:" . ((in_array("x", $error["errors"])) ? "red" : "green") .
+					";'>{$error['data']['gx']}</span> ({$ok->x}), y = <span style='color:" . ((in_array("y", $error["errors"])) ? "red" : "green") .
+					";'>{$error['data']['gy']}</span> ({$ok->y}), epsg = <span style='color:" . ((in_array("epsg", $error["errors"])) ? "red" : "green") .
+					";'>{$error['data']['EPSG']}</span>" . ((in_array("epsg", $error["errors"])) ? " ({$ok->epsg})" : "") . "<br/>";
+			}
+			$echo .= '</pre><div style="text-align:center;"><a href="?_route=GeoreferencesManager&action=repairPoints" class="btn btn-primary">Napraw wszystkie</a></div>';
+			SE_Layout::alert('warning', $echo);
+		}
+
+		if (isset($errorsData["nonunfuckable"])) {
+			$echo = '<b>Znalezione błędy, których nie można automatycznie naprawić:</b></br/><pre>';
+			foreach ($errorsData["nonunfuckable"] as $error) {
+				$echo .= "[{$error['data']['ID']}] the_geom = " . ((!($error['data']['gx'] || $error['data']['gy'])) ? "NULL" : "POINT({$error['data']['gx']} {$error['data']['gy']})") .
+					", x = {$error['data']['x']}, y = {$error['data']['y']}, epsg = {$error['data']['EPSG']}<br/>";
+			}
+			$echo .= '</pre>';
+			SE_Layout::alert('danger', $echo);
+		}
+
+		if (!$errorsData) {
+			SE_Layout::alert('success', "Wszystko OK");
+		}
+	}
+
+	private function repairPoints() {
+		$errorsData = self::getBadPoints()["unfuckable"];
+		$updateErrors = [];
+		$updateSuccess = 0;
+		foreach ($errorsData as $ID => $error) {
+			$ok = epsgConversion::PUWGToLonLatWGS84($error['data']['x'], $error['data']['y']);
+			$sqlArr = [
+				"ID" => $ID,
+				"the_geom" => "GeomFromText('POINT({$ok->x} {$ok->y})')",
+				"EPSG" => $ok->epsg
+			];
+			try {
+				if (DB::getDB()->UPDATE_OBJ(self::TABLE, $sqlArr) < 1) $updateErrors[] = $ID;
+				else $updateSuccess++;
+			} catch (Exception $e) {
+				$updateErrors[] = $ID;
+			}
+		}
+		$echo = "Zaktualizowano {$updateSuccess} z " . count($errorsData) . " rekordów.";
+		if ($updateErrors) {
+			$echo .= "<br/>Nie zaktualizowano rekordów ID: " . implode(", ", $updateErrors);
+			SE_Layout::alert('danger', $echo);
+		} else SE_Layout::alert('success', $echo);
+	}
+
+	private function uploadPoints() {
+		$subActions = ["uploadPointsConfirm", "uploadPointsSave"];
+		if (!in_array($subAction = V::get('subAction','',$_POST), $subActions)) $subAction = "uploadPointsForm";
+		$this->$subAction();
+	}
+
+	private function uploadPointsConfirm() {
+		try {
+			$maxDistance = V::get('maxDistance','ERROR',$_POST);
+			if (!is_numeric($maxDistance)) throw new Exception("Błąd formularza #1");
+			if (!isset($_FILES['file'])) throw new Exception("Błąd formularza #2");
+			if (!file_exists($_FILES['file']['tmp_name'])) throw new Exception("Wystąpił problem z przesłaniem pliku");
+			if ($_FILES['file']['type'] != 'text/csv') throw new Exception("Błędny typ pliku - {$_FILES['file']['type']}");
+			$file = file($_FILES['file']['tmp_name']);
+
+			$points = [];
+			foreach ($file as $line) {
+				list($lp, $y, $x, $z, $type) = explode(',', $line);
+				if (!($lp && $x && $y && $z && $type)) throw new Exception("Plik zawiera niepoprawne dane");
+				if (trim($type) == "Pikieta") {
+					foreach ($points as $key => $point) {
+						if (sqrt((pow($point['x'] - $x, 2) + pow($point['y'] - $y, 2)) <= $maxDistance)) {
+							$lp = $key;
+							break;
+						}
 					}
+					$points[$lp] = ['x' => $x, 'y' => $y, 'z' => $z];
 				}
 			}
-		}
+
+			if (!$points) throw new Exception("Plik zawiera niepoprawne dane");
+
+			$tempTbl = self::TABLE . "_temp";
+			DB::getPDO()->query("CREATE TEMPORARY TABLE `{$tempTbl}` (SELECT * FROM `" . self::TABLE . "`)");
+			$result = DB::getPDO()->fetchall("SELECT ID, x(the_geom) AS gx, y(the_geom) AS gy FROM `{$tempTbl}` WHERE ST_IsEmpty(the_geom) = 0 AND x = 0 AND y = 0");
+			foreach ($result as $row) {
+				$puwg = epsgConversion::LonLatToPUWGWGS84($row['gx'], $row['gy']);
+				DB::getPDO()->query("UPDATE `{$tempTbl}` SET x = '{$puwg->x}', y = '{$puwg->y}' WHERE ID='{$row['ID']}'");
+			}
+
+			$duplicates = [];
+			$closePoints = [];
+			foreach ($points as $lp => $point) {
+				$result = DB::getPDO()->fetchall("SELECT ID, SQRT(POW('{$point['x']}' - x, 2) + POW('{$point['y']}' - y, 2)) as distance, z FROM `{$tempTbl}` ORDER BY distance LIMIT 1");
+				if ($result) {
+					if (in_array($result[0]['ID'], $closePoints)) $duplicates[$lp] = array_search($result[0]['ID'], $closePoints);
+					($duplicates[$lp] = array_search($result[0]['ID'], $closePoints)) ?: $closePointsDetail[$lp] = $result[0];
+					$closePoints[$lp] = $result[0]['ID'];
+				}
+				else $closePointsDetail[$lp] = false;
+				$wgs84[$lp] = epsgConversion::PUWGToLonLatWGS84($point['x'], $point['y']);
+			}
 ?>
-  <div class="form-group">
-    <div class="col-sm-12"><br/>
+    <style>
+      <!--
+      .table > tbody > tr > td {vertical-align: middle};
+      -->
+    </style>
+    <form class="form-horizontal" method="post" enctype="multipart/form-data">
+      <div class="form-group">
+        <div class="col-sm-12">
+          <table class="table table-bordered table-hover table-striped">
+            <thead>
+              <tr style="text-align:center; background-color:lightgray"><td>Lp.</td><td>X</td><td>Y</td><td>Z (m)</td><td>EPSG</td><td>Znaleziony najbliższy punkt (w odległości w metrach)</td><td>Działanie</td></tr>
+            </thead>
+            <tbody>
 <?php
-//$errors = [];
-//		if ($errors) echo "<pre>" . implode("<br/>", $errors) . "</pre>";
-		if ($errors) {
-			SE_Layout::alert('danger', "<pre>" . implode("<br/>", $errors) . "</pre>");
+			$i = 0;
+			foreach ($points as $lp => $point) {
+				$disabled = false;
+				$checked = true;
+				echo "<tr><td nowrap align='right'>" . ++$i . "</td><td nowrap>{$point['x']} ({$wgs84[$lp]->x})</td><td nowrap>{$point['y']} ({$wgs84[$lp]->y})</td><td nowrap>{$point['z']}</td><td nowrap align='center'>{$wgs84[$lp]->epsg}</td><td nowrap>";
+				if ($closePointsDetail[$lp]) {
+					if ($closePointsDetail[$lp]['distance'] == 0) {
+						if ($closePointsDetail[$lp]['z']) {
+							if ($closePointsDetail[$lp]['z'] == $point['z']) {
+								echo "ID:{$closePoints[$lp]} - to ten sam punkt, nie ma co aktualiować";
+								$disabled = true;
+							} else echo "ID:{$closePoints[$lp]} - to ten sam punkt, ale z inną wartością Z -<br/>należy zaktualizować";
+						} else echo "ID:{$closePoints[$lp]} - to ten sam punkt, ale wcześniej nie został zweryfikowany -<br/>należy zaktualiować";
+					} elseif ($closePointsDetail[$lp]['distance'] <= $maxDistance) echo "ID:{$closePoints[$lp]} ({$closePointsDetail[$lp]['distance']}) - należy zaktualizować";
+					else {
+						echo "ID:{$closePoints[$lp]} ({$closePointsDetail[$lp]['distance']}) - za daleko, zdecyduj co zrobić";
+						$checked = false;
+					}
+				} elseif (isset($duplicates[$lp])) {
+					echo "ID:{$closePoints[$lp]} - ten sam punkt został znaleziony dla punktu Lp. {$duplicates[$lp]} -<br/>nie można zaktualizować z powodu konfliktu<br/>(zalecia się ponowne wgranie tego samego pliku po dodaniu pozostałych punktów)";
+					$disabled = true;
+				} else echo "Nie znaleziono żadnego punktu - należy dodać nowy";
+				echo "</td><td nowrap>";
+				if ($closePointsDetail[$lp]['distance'] <= $maxDistance) echo "<div class='checkbox'><label><input type='checkbox' name='points[{$lp}]'" .
+					($disabled ? " disabled" : ($checked ? " checked" : "")) . "/>" . ($closePoints[$lp] ? "Zaktualizuj" : "Dodaj nowy") . "</label></div>";
+				else {
 ?>
-    <div style="text-align:center;"><a href="?_route=GeoreferencesManager&action=repairPoints" class="btn btn-primary">Napraw wszystkie</a></div>
+<div class='radio'><label><input type='radio' name='points[<?=$lp?>]' value='new' checked/>Dodaj nowy</label></div>
+<div class='radio'><label><input type='radio' name='points[<?=$lp?>]' value='on'/>Zaktualizuj</label></div>
+<div class='radio'><label><input type='radio' name='points[<?=$lp?>]' value='off'/>Zignoruj</label></div>
 <?php
-		} else SE_Layout::alert('success', "Wszystko OK"); //echo "<span style='color:green;'>Wszystko OK</span>";
+				}
+				echo "</td></tr>";
+			}
 ?>
-    </div>
-  </div>
+            </tbody>
+          </table>
+          <div style="text-align:center;"><button type="submit" class="btn btn-primary" name="subAction" value="uploadPointsSave">Zapisz</button></div>
+        </div>
+      </div>
+    </form>
 <?php
+			$_SESSION['uploadPointsData'] = gzcompress(json_encode(['points' => $points, 'closePoints' => $closePoints]));
+
+		} catch (Exception $e) {
+			SE_Layout::alert('danger', $e->getMessage());
+			$this->uploadPointsForm();
+		}
 	}
 
+	private function uploadPointsSave() {
+		try {
+			if (!isset($_SESSION['uploadPointsData'])) throw new Exception("Błąd danych #1");
+			$data = json_decode(gzuncompress($_SESSION['uploadPointsData']), true);
+			if (!$data) throw new Exception("Błąd danych #2");
+			$points = V::get('points','',$_POST);
+			if (!is_array($points)) throw new Exception("Błąd danych #3");
+			$points = array_diff($points, ["off"]);
+			if (!$points) throw new Exception("Nie zdefiniowany żadnych punktów do aktualizacji/dodania");
+			foreach ($points as $lp => $action) {
+				$x = $data['points'][$lp]['x'];
+				$y = $data['points'][$lp]['y'];
+				$z = $data['points'][$lp]['z'];
+				try {
+					$wgs84 = epsgConversion::PUWGToLonLatWGS84($x, $y);
+					$gx = $wgs84->x;
+					$gy = $wgs84->y;
+					$epsg = $wgs84->epsg;
+					$the_geom = "GeomFromText('POINT({$gx} {$gy})')";
+					$sqlArrs[$lp] = [
+						"A_STATUS" => "NORMAL",
+						"A_STATUS_INFO" => "Punkt uzgodniony automatycznie",
+						"the_geom" => $the_geom,
+						"x" => $x,
+						"y" => $y,
+						"z" => $z,
+						"EPSG" => $epsg
+					];
+					if ($action == "on") {
+						if (!isset($data['closePoints'][$lp])) throw new Exception("Błąd danych #3");
+						$sqlArrs[$lp]['ID'] = $data['closePoints'][$lp];
+					} elseif ($action != "new") throw new Exception("Błąd danych #4");
+				} catch (Exception $e) {
+					SE_Layout::alert('danger'," Wystąpił problem (#1) z dodaniem punktu Lp. {$lp} - {$e->getMessage()}");
+				}
+			}
+
+			$i = 0;
+			foreach ($sqlArrs as $lp => $sqlArr) {
+				try {
+					if (isset($sqlArr['ID'])) $affected = DB::getDB()->UPDATE_OBJ(self::TABLE, $sqlArr);
+					else $affected = DB::getDB()->ADD_NEW_OBJ(self::TABLE, $sqlArr);
+					if ($affected < 1) throw new Exception("Błąd bazy danych: " . print_r($sqlArr, true));
+					$i++;
+				} catch (Exception $e) {
+					SE_Layout::alert('danger', "Wystąpił problem (#2) z dodaniem punktu Lp. {$lp} - {$e->getMessage()}");
+				}
+				
+			}
+
+			if ($i > 0) SE_Layout::alert(($i == count($sqlArrs) ? "success" : "warning"), "Pomyślnie dodano/zaktualizowano {$i} z " . count($sqlArrs) . " punktów");
+			else SE_Layout::alert('danger', "Nie dodano/zaktualiowano żadnego punktu");
+		} catch (Exception $e) {
+			SE_Layout::alert('danger', $e->getMessage());
+			$this->uploadPointsForm();
+		}
+	}
+
+	private function uploadPointsForm() {
+?>
+    <form class="form-horizontal" method="post" enctype="multipart/form-data">
+      <div class="form-group">
+        <label class="col-sm-4 control-label">Wybierz plik z punktami georeferencyjnymi</label>
+        <div class="col-sm-8" style="margin-top:7px;">
+          <input type="hidden" name="subAction" value="uploadPointsConfirm">
+          <input type="file" name="file" required/>
+        </div>
+      </div>
+      <div class="form-group">
+        <label class="col-sm-4 control-label">Maksymalna odległość istniejącego punktu (w metrach)</label>
+        <div class="col-sm-1">
+          <input type="number" class="form-control" name="maxDistance" data-bind="value:replyNumber" min="1" value="50" required>
+        </div>
+      </div>
+      <div class="form-group">
+         <div class="col-sm-offset-4 col-sm-8">
+           <button type="submit" class="btn btn-primary" name="subAction" value="uploadPointsConfirm">Wgraj plik</button>
+         </div>
+      </div>
+    </form>
+<?php
+	}
 }