Jelajahi Sumber

getCsvTheGeom - implementacja kolizji

Mariusz Muszyński 8 tahun lalu
induk
melakukan
5e775744ad
1 mengubah file dengan 68 tambahan dan 38 penghapusan
  1. 68 38
      SE/se-lib/Route/ViewTableAjax.php

+ 68 - 38
SE/se-lib/Route/ViewTableAjax.php

@@ -637,59 +637,89 @@ class Route_ViewTableAjax extends RouteBase {
 		}
 	}
 
-	public function getCsvTheGeomAjax($minDistance = 10) {
+	public function getCsvTheGeomAjax($minDistance = 10, $nearDistance = 1) {
 		Lib::loadClass('EpsgConversion');
+		Lib::loadClass('Geometry');
+
 		$namespace = V::get('namespace', '', $_GET, 'word');
 		$acl = Core_AclHelper::getAclByNamespace($namespace);
 		$table = $acl->getRootTableName();
 		$id = V::get('id', 0, $_GET, 'int');
 
-		$query = "select st_astext(`the_geom`) as `the_geom` from `{$table}` where `ID` = {$id}";
-		try {
-			$result = DB::getPDO()->fetchValue($query);
-		} catch (Exception $e) {
-			throw new Exception('Błąd zapytania SQL');
-		}
-		if (!preg_match('/^[[:alpha:]]+\((.*)\)$/', $result, $matches)) throw new Exception('Błąd danych georeferencyjnych');
-		$points = explode(',', $matches[1]);
-
-		$calcDistance = function($x1, $y1, $x2, $y2) {
-			return sqrt(pow($x1 - $x2, 2) + pow($y1 - $y2, 2));
-		};
+		$query_points = "select st_astext(`the_geom`) as `the_geom` from `{$table}` where `ID` = {$id}";
+		$result_points = DB::getPDO()->fetchValue($query_points);
+		$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']];
+		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`)";
+			$results_nears = DB::getPDO()->fetchAll($query_nears);
+			$nears = [];
+			foreach ($results_nears as $result_nears) {
+				$nears = array_merge($nears, Geometry::pointsToLines(Geometry::objectFromText($result_nears['the_geom'], 'Wgs84ToPuwg2000')->points()));
+			}
 
-		$lastX = null; $lastY = null;
-		$csv = implode("\n", array_map(function ($point, $i) use (&$lastX, &$lastY, $calcDistance, $minDistance) {
-			$return = '';
-			list($x, $y) = explode(" ", $point, 2);
-			$puwg2000 = EpsgConversion::Wgs84ToPuwg2000($x, $y);
-
-			if ($lastX !== null) {
-				if (($distance = $calcDistance($lastX, $lastY, $puwg2000->x, $puwg2000->y)) > $minDistance) {
-					$parts = ceil($distance / $minDistance);
-					$deltaX = ($puwg2000->x - $lastX) / $parts;
-					$deltaY = ($puwg2000->y - $lastY) / $parts;
-					for ($j = 1; $j < $parts; $j++) {
-						$partX = round($lastX + $j * $deltaX, 3);
-						$partY = round($lastY + $j * $deltaY, 3);
-						try {
-							$partZ = round(EpsgConversion::GetZByPuwg2000($partX, $partY), 3);
-						} catch (Exception $e) {
-							$partZ = 0;
-						}
-						$return .= ($i - 1) . ".{$j},{$partY},{$partX},{$partZ},Punkt posredni\n";
+			$nears = array_filter($nears, function ($near) use ($line, $nearDistance) {
+				return Geometry::distance($line, $near) <= $nearDistance;
+			});
+
+			$ki = 1;
+			$lastNear = null;
+			$mergedNears = [];
+			foreach ($nears as $near) {
+				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)'];
+							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'];
+							break;
+						default:
+							throw new Exception(__CLASS__ . "::" . __FUNCTION__ . ' - unknown error');
 					}
 				}
+				if ($lastNear) {
+					if (Geometry::samePoint($lastNear->b, $near->a)) $lastNear->b = $near->b;
+					else $mergedNears[] = $lastNear;
+				}
+				$lastNear = $near;
 			}
-			$lastX = $puwg2000->x; $lastY = $puwg2000->y;
+			if ($lastNear) $mergedNears[] = $lastNear;
 
+			foreach ($mergedNears as $near) {
+				$a = Geometry::closedPointOnLine($near->a, $line);
+				$b = Geometry::closedPointOnLine($near->b, $line);
+				$array[] = ['i' => ($i - 1) . '.k' . $ki . 'a', 'x' => $a->x, 'y' => $a->y, 'desc' => 'Kolizja (II) start'];
+				$array[] = ['i' => ($i - 1) . '.k' . $ki++ . 'b', 'x' => $b->x, 'y' => $b->y, 'desc' => 'Kolizja (II) stop'];
+			}
+
+			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'];
+				}
+			}
+
+			$array[] = ['i' => $i, 'x' => $line->b->x, 'y' => $line->b->y, 'desc' => 'Punkt'];
+			$i++;
+		}
+
+		$csv = implode("\n", array_map(function ($item) {
 			try {
-				$z = EpsgConversion::GetZByWgs84($x, $y);
+				$z = EpsgConversion::GetZByPuwg2000($item['x'], $item['y']);
 			} catch (Exception $e) {
 				$z = 0;
 			}
-			$return .= $i . ',' . round($puwg2000->y, 3) . ',' . round($puwg2000->x, 3) . ',' . round($z, 3) . ',Punkt';
-			return $return;
-		}, $points, range(1, count($points))));
+			return $item['i'] . "," . round($item['y'], 3) . "," . round($item['x'], 3) . "," . round($z, 3) . "," . $item['desc'];
+		}, $array));
+
 		Response::sendCsv($csv, "{$table}.{$id}");
 	}