瀏覽代碼

Poprawki do funkcji generującej plik CSV z punktami georeferencyjnymi (błędnie generowały się kolizje)

Mariusz Muszyński 8 年之前
父節點
當前提交
af8fcb08a2
共有 1 個文件被更改,包括 110 次插入27 次删除
  1. 110 27
      SE/se-lib/Route/ViewTableAjax.php

+ 110 - 27
SE/se-lib/Route/ViewTableAjax.php

@@ -651,8 +651,10 @@ class Route_ViewTableAjax extends RouteBase {
 		$points = Geometry::objectFromText($result_points, 'Wgs84ToPuwg2000')->points();
 		$lines = Geometry::pointsToLines($points);
 
-		$i = 1;
-		$array = [['i' => $i++, 'x' => $points[0]->x, 'y' => $points[0]->y, 'desc' => 'Punkt']];
+		// Dodanie początkowego punktu pierwszej linii do tabeli wszystkcih punktów
+		$_points = [['point' => $points[0], 'type' => ['p']]];
+
+		// Szukanie kolzji dla każdej linii prostej
 		foreach ($lines as $line) {
 			$polygon_asText = Geometry::lineToRectangle($line, $nearDistance)->asText('Puwg2000ToWgs84');
 			$query_nears = "select st_astext(`the_geom`) as `the_geom` from `rurociagi_obce_wsg84` where st_intersects(st_geomfromtext('{$polygon_asText}'), `the_geom`)";
@@ -666,71 +668,152 @@ class Route_ViewTableAjax extends RouteBase {
 				return Geometry::distance($line, $near) <= $nearDistance;
 			});
 
-			$ki = 1;
-			$lastNear = null;
-			$nearsOnLine = [];
+			// Szukanie odcinków kolizyjnych
+			$crossPoints = [];
+			$_nearsOnLine = [];
 			foreach ($nears as $near) {
-				if ($crossPoints = Geometry::crossPoint($line, $near)) {
-					switch (count($crossPoints)) {
+				if ($_crossPoints = Geometry::crossPoint($line, $near)) {
+					switch (count($_crossPoints)) {
 						case 1:
-							$array[] = ['i' => ($i - 1) . '.k' . $ki++, 'x' => $crossPoints[0]->x, 'y' => $crossPoints[0]->y, 'desc' => 'Kolizja (X)'];
+							// Znaleziono kolizję przecinającą linię
+							$crossPoints[] = ['point' => $_crossPoints[0], 'type' => ['x']];
 							break;
 						case 2:
-							$array[] = ['i' => ($i - 1) . '.k' . $ki . 'a', 'x' => $crossPoint->x, 'y' => $crossPoint->y, 'desc' => 'Kolizja (I) start'];
-							$array[] = ['i' => ($i - 1) . '.k' . $ki++ . 'b', 'x' => $crossPoint->x, 'y' => $crossPoint->y, 'desc' => 'Kolizja (I) stop'];
+							// Znaleziono kolizję idealnie nałożoną na linię
+							$_nearsOnLine[] = Geometry::line($_crossPoints[0], $_crossPoints[1]);
 							break;
 						default:
 							throw new Exception(__CLASS__ . "::" . __FUNCTION__ . ' - unknown error');
 					}
-				} else $crossPoints = [];
+				}
 
-				$nearOnLine = Geometry::line(Geometry::closedPointOnLine($near->a, $line), Geometry::closedPointOnLine($near->b, $line));
+				// Analiza pobliskich kolizji
+				$a = Geometry::closedPointOnLine($near->a, $line);
+				$b = Geometry::closedPointOnLine($near->b, $line);
+				if (Geometry::distance($a, $line->a) < Geometry::distance($b, $line->a)) $nearOnLine = Geometry::line($a, $b);
+				else $nearOnLine = Geometry::line($b, $a);
 
+				// Weryfikacja czy pobliska kolizja nie jest jednocześnie kolizją przecinajacą i czy nie jest za krótka (<1m) - wtedy ją usuwamy
+				$add = true;
 				if ($nearOnLine->length() < 1) {
-					$break = false;
 					foreach ($crossPoints as $crossPoint) {
-						if (Geometry::distance($crossPoint, $nearOnLine) == 0) {
-							$break = true;
+						if (Geometry::distance($crossPoint['point'], $nearOnLine) == 0) {
+							$add = false;
 							break;
 						}
 					}
-					if ($break) continue;
 				}
+				if ($add) $_nearsOnLine[] = $nearOnLine;
+			}
+
+			// Przesortowanie wszystkich kolizji linowych
+			usort($_nearsOnLine, function ($A, $B) use ($line) {
+				if (Geometry::samePoint($A->a, $B->a)) return 0;
+				if (Geometry::distance($A, $line->a) < Geometry::distance($B, $line->a)) return -1;
+				return 1;
+			});
 
+			// Scalenie wszystkich kolizji jeżeli odstęp między nimi jest krótszy niz 1m
+			$lastNearOnLine = null;
+			$nearsOnLine = [];
+			foreach ($_nearsOnLine as $nearOnLine) {
 				if ($lastNearOnLine) {
-					if (Geometry::distance($lastNearOnLine->b, $nearOnLine->a) < 1) $lastNearOnLine->b = $nearOnLine->b;
-					else $nearsOnLine[] = $lastNearOnLine;
+					if (Geometry::distance($nearOnLine, $lastNearOnLine) < 1) {
+						$nearOnLine->a = $lastNearOnLine->a;
+						if (Geometry::distance($nearOnLine->b, $line->a) < Geometry::distance($lastNearOnLine->b, $line->a)) $nearOnLine->b = $lastNearOnLine->b;
+					} else $nearsOnLine[] = $lastNearOnLine;
 				}
 				$lastNearOnLine = $nearOnLine;
 			}
 			if ($lastNearOnLine) $nearsOnLine[] = $lastNearOnLine;
 
+			// Nałożenie kolizji liniowych na punkty kolizyjne
 			foreach ($nearsOnLine as $nearOnLine) {
-				$array[] = ['i' => ($i - 1) . '.k' . $ki . 'a', 'x' => $nearOnLine->a->x, 'y' => $nearOnLine->a->y, 'desc' => 'Kolizja (II) start'];
-				$array[] = ['i' => ($i - 1) . '.k' . $ki++ . 'b', 'x' => $nearOnLine->b->x, 'y' => $nearOnLine->b->y, 'desc' => 'Kolizja (II) stop'];
+				$crossPoints[] = ['point' => $nearOnLine->a, 'type' => ['iistart']];
+				$crossPoints[] = ['point' => $nearOnLine->b, 'type' => ['iistop']];
 			}
 
+			// Podzielenie linii prostej na krótsze odcinki, jezeli jest zbyt długa (>$minDistance)
 			if (($distance = $line->length()) > $minDistance) {
 				$parts = ceil($distance / $minDistance);
 				$deltaX = ($line->b->x - $line->a->x) / $parts;
 				$deltaY = ($line->b->y - $line->a->y) / $parts;
 				for ($j = 1; $j < $parts; $j++) {
-					$array[] = ['i' => ($i - 1) . "." . $j, 'x' => ($line->a->x + $j * $deltaX), 'y' => ($line->a->y + $j * $deltaY), 'desc' => 'Pośredni'];
+					$_point = Geometry::point($line->a->x + $j * $deltaX, $line->a->y + $j * $deltaY);
+					$collision = false;
+					foreach ($nearsOnLine as $nearOnLine) {
+						if (Geometry::distance($nearOnLine, $_point) == 0) {
+							$collision = true;
+							break;
+						}
+					}
+					$type = ['m'];
+					if ($collision) $type[] = 'ii';
+					$crossPoints[] = ['point' => Geometry::point($line->a->x + $j * $deltaX, $line->a->y + $j * $deltaY), 'type' => $type];
 				}
 			}
 
-			$array[] = ['i' => $i, 'x' => $line->b->x, 'y' => $line->b->y, 'desc' => 'Punkt'];
-			$i++;
+			// Przesortowanie wszystkich punktów na linii
+			usort($crossPoints, function ($a, $b) use ($line) {
+				if (Geometry::samePoint($a['point'], $b['point'])) return 0;
+				if (Geometry::distance($a['point'], $line->a) < Geometry::distance($b['point'], $line->a)) return -1;
+				return 1;
+			});
+
+			// Dodanie wszystkich punktów kolizyjnych i pośrednich do tabeli wszystkich punktów
+			foreach ($crossPoints as $crossPoint) $_points[] = ['point' => $crossPoint['point'], 'type' => $crossPoint['type']];
+
+			// Dodanie końcowego punktu linii do tabeli wszystkich punktów
+			$_points[] = ['point' => $line->b, 'type' => ['p']];
+		}
+
+		// Połączenie kilku takich samych punktów w jeden punkt (np. punkt początku linii oraz punkt początku kolizji - gdy wypadają w tym samym miejscu)
+		$points = [];
+		$lastPoint = null;
+		$desc = [];
+		foreach ($_points as $point) {
+			if ($lastPoint) {
+				if (Geometry::samePoint($point['point'], $lastPoint['point'])) $point['type'] = array_merge($lastPoint['type'], $point['type']);
+				else $points[] = $lastPoint;
+			}
+			$lastPoint = $point;
 		}
+		if ($lastPoint) $points[] = $lastPoint;
+
+		// Funkcja generująca czytelny opis rodzaju punktu
+		$typeToDesc = function($type) {
+			if (in_array('iistart', $type) && in_array('iistop', $type)) {
+				$type = array_diff($type, ['iistart', 'iistop']);
+				$type[] = 'ii';
+			}
+			usort($type, function($a, $b) {
+				if ($a == 'p' || $a == 'm') return -1;
+				if ($b == 'p' || $b == 'm') return 1;
+				return 0;
+			});
+			return implode('|', array_map(function($_type) {
+				$types = [
+					'p' => 'Punkt',
+					'm' => 'Posredni',
+					'x' => 'Kolizja (X)',
+					'ii' => 'Kolizja (II)',
+					'iistart' => 'Kolizja (II) start',
+					'iistop' => 'Kolizja (II) stop'
+				];
+				if (!in_array($_type, $types)) return $types[$_type];
+				throw new Exception("Nieznany typ punktu - {$_type} (" . __CLASS__ . '::' . __FUNCTION__ . ')');
+			}, $type));
+		};
 
-		$csv = implode("\n", array_map(function ($item) {
+		// Generowanie pliku CSV
+		$csv = implode("\n", array_map(function ($point, $i) use ($typeToDesc) {
 			try {
-				$z = EpsgConversion::GetZByPuwg2000($item['x'], $item['y']);
+				$z = EpsgConversion::GetZByPuwg2000($point['point']->x, $point['point']->y);
 			} catch (Exception $e) {
 				$z = 0;
 			}
-			return $item['i'] . "," . round($item['y'], 3) . "," . round($item['x'], 3) . "," . round($z, 3) . "," . $item['desc'];
-		}, $array));
+			return $i . "," . round($point['point']->y, 3) . "," . round($point['point']->x, 3) . "," . round($z, 3) . "," . $typeToDesc($point['type']);
+		}, $points, range(1, count($points))));
 
 //		echo "<pre>{$csv}</pre>";
 		Response::sendCsv($csv, "{$table}.{$id}");