diff --git a/app/Validators/Extensions/Polygons/NotOverlapping.php b/app/Validators/Extensions/Polygons/NotOverlapping.php index d8d039696..de9862bcc 100644 --- a/app/Validators/Extensions/Polygons/NotOverlapping.php +++ b/app/Validators/Extensions/Polygons/NotOverlapping.php @@ -24,19 +24,21 @@ public static function passes($attribute, $value, $parameters, $validator): bool public static function getIntersectionData(string $polygonUuid): array { $sitePolygon = SitePolygon::forPolygonGeometry($polygonUuid)->first(); - if ($sitePolygon === null) { - return [ - 'valid' => false, - 'error' => 'Site polygon not found for the given polygon ID', - 'status' => 404, - ]; + if (! $sitePolygon) { + return ['valid' => false, 'error' => 'Site polygon not found', 'status' => 404]; } $relatedPolyIds = $sitePolygon->project->sitePolygons() ->where('poly_id', '!=', $polygonUuid) ->pluck('poly_id'); - $intersects = PolygonGeometry::join('site_polygon', 'polygon_geometry.uuid', '=', 'site_polygon.poly_id') + + $bboxFilteredPolyIds = PolygonGeometry::join('site_polygon', 'polygon_geometry.uuid', '=', 'site_polygon.poly_id') ->whereIn('polygon_geometry.uuid', $relatedPolyIds) + ->whereRaw('ST_Intersects(ST_Envelope(polygon_geometry.geom), (SELECT ST_Envelope(geom) FROM polygon_geometry WHERE uuid = ?))', [$polygonUuid]) + ->pluck('polygon_geometry.uuid'); + + $intersects = PolygonGeometry::join('site_polygon', 'polygon_geometry.uuid', '=', 'site_polygon.poly_id') + ->whereIn('polygon_geometry.uuid', $bboxFilteredPolyIds) ->select([ 'polygon_geometry.uuid', 'site_polygon.poly_name', @@ -50,28 +52,27 @@ public static function getIntersectionData(string $polygonUuid): array $mainPolygonArea = PolygonGeometry::where('uuid', $polygonUuid) ->value(DB::raw('ST_Area(geom)')); - $extra_info = []; - foreach ($intersects as $intersect) { - if ($intersect->intersects) { + + $extra_info = $intersects + ->filter(fn ($intersect) => $intersect->intersects) + ->map(function ($intersect) use ($mainPolygonArea) { $minArea = min($mainPolygonArea, $intersect->area); - if ($minArea > 0) { - $percentage = ($intersect->intersection_area / $minArea) * 100; - $percentage = round($percentage, 2); - } else { - $percentage = 100; - } - $extra_info[] = [ + $percentage = $minArea > 0 + ? round(($intersect->intersection_area / $minArea) * 100, 2) + : 100; + + return [ 'poly_uuid' => $intersect->uuid, 'poly_name' => $intersect->poly_name, 'percentage' => $percentage, 'intersectSmaller' => ($intersect->area < $mainPolygonArea), ]; - } - } - + }) + ->values() + ->toArray(); return [ - 'valid' => ! $intersects->contains('intersects', 1), + 'valid' => empty($extra_info), 'uuid' => $polygonUuid, 'project_id' => $sitePolygon->project_id, 'extra_info' => $extra_info, diff --git a/database/factories/V2/PolygonGeometryFactory.php b/database/factories/V2/PolygonGeometryFactory.php index bea9177a1..5c75a788c 100644 --- a/database/factories/V2/PolygonGeometryFactory.php +++ b/database/factories/V2/PolygonGeometryFactory.php @@ -16,11 +16,14 @@ public function definition() public function geojson(string|array $geojson) { - $geom = DB::raw("ST_GeomFromGeoJSON('$geojson')"); + if (is_array($geojson)) { + $geojson = json_encode($geojson); + } + $geomExpression = DB::raw("ST_GeomFromGeoJSON('$geojson')"); - return $this->state(function (array $attributes) use ($geom) { + return $this->state(function (array $attributes) use ($geomExpression) { return [ - 'geom' => $geom, + 'geom' => $geomExpression, ]; }); } diff --git a/database/factories/V2/Sites/SitePolygonFactory.php b/database/factories/V2/Sites/SitePolygonFactory.php index 1e8415ca5..13d595f0c 100644 --- a/database/factories/V2/Sites/SitePolygonFactory.php +++ b/database/factories/V2/Sites/SitePolygonFactory.php @@ -10,8 +10,24 @@ class SitePolygonFactory extends Factory { public function definition() { + $geojson = [ + 'type' => 'Polygon', + 'coordinates' => [ + [ + [0, 0], + [1, 0], + [1, 1], + [0, 1], + [0, 0], + ], + ], + ]; + return [ - 'poly_id' => PolygonGeometry::factory()->create()->uuid, + 'poly_id' => PolygonGeometry::factory() + ->geojson($geojson) + ->create() + ->uuid, 'site_id' => Site::factory()->create()->uuid, 'calc_area' => $this->faker->numberBetween(2.0, 50.0), ]; diff --git a/database/migrations/2024_11_26_154102_add_spatial_index_to_polygon_geometry.php b/database/migrations/2024_11_26_154102_add_spatial_index_to_polygon_geometry.php new file mode 100644 index 000000000..1a2e14336 --- /dev/null +++ b/database/migrations/2024_11_26_154102_add_spatial_index_to_polygon_geometry.php @@ -0,0 +1,30 @@ +index('poly_id', 'idx_site_polygon_poly_id'); + }); + } + + public function down(): void + { + Schema::table('site_polygon', function (Blueprint $table) { + $table->dropIndex('idx_site_polygon_poly_id'); + }); + } +};