added geojson extractor

This commit is contained in:
noyamii
2025-08-19 14:02:59 +03:30
parent c2be14a183
commit d2afe15a2f
3 changed files with 164 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
<?php
namespace App\Console\Commands;
use App\Models\City;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use function Symfony\Component\String\b;
class ExtractGeometryForCities extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:extract-geometry-for-cities {jsonPath}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This command will extract polygons for cities from the given .json file';
/**
* Execute the console command.
*/
public function handle()
{
$jsonPath = $this->argument('jsonPath');
$json = File::get($jsonPath);
$data = json_decode($json, true);
$features = $data['features'] ?? null;
if ($features === null) {
$this->error('No features were found');
return parent::FAILURE;
}
foreach ($data['features'] as $city) {
$cityId = $city['properties']['city_id'] ?? null;
if ($cityId === null)
{
$this->info("this city doesn't have id: $city");
continue;
}
$coordinates = $city['geometry']['coordinates'] ?? null;
if ($coordinates === null)
{
$this->info("this city doesn't have coordinates: $coordinates");
continue;
}
$type = $city['geometry']['type'] ?? null;
if ($type === null)
{
$this->info("This city doesn't have a type: $city");
continue;
}
try {
switch ($type) {
case 'Polygon':
$wktCoords = collect($coordinates[0])
->map(fn($pair) => $pair[1] . ' ' . $pair[0])
->implode(',');
$wellKnownText = "POLYGON(($wktCoords))";
break;
case 'MultiPolygon':
$wktCoords = collect($coordinates)
->map(function ($polygon) {
$rings = collect($polygon)->map(function ($ring) {
if ($ring[0] !== end($ring)) {
$ring[] = $ring[0];
}
return collect($ring)
->map(fn($pair) => $pair[1] . ' ' . $pair[0])
->implode(',');
});
return '((' . $rings->implode('),(') . '))';
})
->implode(',');
$wellKnownText = "MULTIPOLYGON($wktCoords)";
break;
default:
$this->info("$type is not a valid type in city: $city");
continue 2;
}
}
catch (\Throwable $th)
{
$this->error("Something went wrong: $th");
continue;
}
$query = City::query()
->find($cityId);
if (!$query) {
$this->info("City $cityId not found");
continue;
}
try {
$query->update([
'geometry' => DB::raw("ST_GeomFromText('$wellKnownText', 4326)")
]);
}
catch (\Throwable $th)
{
$this->error("Something went wrong: $th");
}
}
return parent::SUCCESS;
}
}

View File

@@ -23,6 +23,10 @@ class City extends Model
'updated_at'
];
protected $fillable = [
'geometry',
];
public function province()
{
return $this->belongsTo('App\Models\Province');

View File

@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('cities', function (Blueprint $table) {
$table->geometry('geometry')->nullable();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('cities', function (Blueprint $table) {
$table->dropColumn('geometry');
});
}
};