<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Form\CityToolType;
|
|
use App\Form\OsmoseToolType;
|
|
use App\Service\OsmoseClient;
|
|
use App\Service\OverpassClient;
|
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
|
use Symfony\Component\HttpFoundation\HeaderUtils;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
|
|
#[Route('/tools')]
|
|
class ToolsController extends AbstractController
|
|
{
|
|
#[Route('/', name: 'app_tools')]
|
|
public function index(): Response
|
|
{
|
|
return $this->render('tools/index.html.twig', [
|
|
]);
|
|
}
|
|
|
|
#[Route('/city', name: 'app_tools_city')]
|
|
public function city(
|
|
Request $request,
|
|
OverpassClient $overpass,
|
|
): Response {
|
|
$form = $this->createForm(CityToolType::class, []);
|
|
$form->add('submit', SubmitType::class, ['label' => 'Générer']);
|
|
|
|
$form->handleRequest($request);
|
|
if ($form->isSubmitted() and $form->isValid()) {
|
|
$areaId = $form->get('area')->getData();
|
|
$query = sprintf('relation["boundary"="administrative"]["admin_level"="8"]["name"](area:%d);', 3600000000 + $areaId); // Cf. <https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL#By_area_.28area.29>
|
|
$json = $overpass->query($query);
|
|
|
|
$response = new StreamedResponse();
|
|
|
|
$response->headers->set('Content-Type', 'text/csv');
|
|
$response->headers->set(
|
|
'Content-Disposition',
|
|
HeaderUtils::makeDisposition(
|
|
HeaderUtils::DISPOSITION_ATTACHMENT,
|
|
sprintf('cities-in-%d.csv', $areaId)
|
|
)
|
|
);
|
|
|
|
$response->setCallback(function () use ($json): void {
|
|
$headings = [
|
|
'name',
|
|
'description',
|
|
'osm',
|
|
'geojson',
|
|
'status',
|
|
];
|
|
|
|
$csv = fopen('php://output', 'a');
|
|
|
|
fputcsv($csv, $headings);
|
|
|
|
$osm = \OSM\OSM::createFromJson($json);
|
|
|
|
foreach ($osm->elements as $relation) {
|
|
$name = $relation->getTagValue('name');
|
|
|
|
$feature = new \GeoJson\Feature\Feature(
|
|
\OSM\GeoJsonConverter::convertRelationToPolygon($relation),
|
|
['name' => $name]
|
|
);
|
|
|
|
fputcsv($csv, [
|
|
$name,
|
|
$name,
|
|
'',
|
|
json_encode(new \GeoJson\Feature\FeatureCollection([$feature])),
|
|
'todo',
|
|
]);
|
|
}
|
|
|
|
fclose($csv);
|
|
});
|
|
|
|
return $response;
|
|
}
|
|
|
|
return $this->render('tools/city.html.twig', [
|
|
'form' => $form,
|
|
]);
|
|
}
|
|
|
|
#[Route('/osmose', name: 'app_tools_osmose')]
|
|
public function osmose(
|
|
Request $request,
|
|
OsmoseClient $osmose,
|
|
OverpassClient $overpass,
|
|
): Response {
|
|
$form = $this->createForm(OsmoseToolType::class, array_merge(['limit' => 500], $request->query->all()));
|
|
$form->add('submit', SubmitType::class, ['label' => 'Générer']);
|
|
|
|
$form->handleRequest($request);
|
|
if ($form->isSubmitted() and $form->isValid()) {
|
|
$issues = $osmose->issues([
|
|
'item' => $form->get('item')->getData(),
|
|
'source' => $form->get('source')->getData(),
|
|
'class' => $form->get('class')->getData(),
|
|
'limit' => $form->get('limit')->getData(),
|
|
'username' => '',
|
|
'bbox' => '',
|
|
'full' => 'true',
|
|
]);
|
|
|
|
$response = new StreamedResponse();
|
|
|
|
$response->headers->set('Content-Type', 'text/csv');
|
|
$response->headers->set(
|
|
'Content-Disposition',
|
|
HeaderUtils::makeDisposition(
|
|
HeaderUtils::DISPOSITION_ATTACHMENT,
|
|
'issues.csv'
|
|
)
|
|
);
|
|
|
|
$issuesGeojson = \GeoJson\GeoJson::jsonUnserialize(json_decode($issues, true));
|
|
|
|
$groupByCity = (bool) $form->get('group_by_city')->getData();
|
|
if ($groupByCity) {
|
|
$minLat = null;
|
|
$maxLat = null;
|
|
$minLon = null;
|
|
$maxLon = null;
|
|
|
|
foreach ($issuesGeojson->getFeatures() as $feature) {
|
|
$geometry = $feature->getGeometry();
|
|
$coordinates = $geometry->getCoordinates();
|
|
$lat = (float) $coordinates[1];
|
|
$lon = (float) $coordinates[0];
|
|
if (is_null($minLat) or ($lat < $minLat)) {
|
|
$minLat = $lat;
|
|
}
|
|
if (is_null($maxLat) or ($lat > $maxLat)) {
|
|
$maxLat = $lat;
|
|
}
|
|
if (is_null($minLon) or ($lon < $minLon)) {
|
|
$minLon = $lon;
|
|
}
|
|
if (is_null($maxLon) or ($lon > $maxLon)) {
|
|
$maxLon = $lon;
|
|
}
|
|
}
|
|
|
|
$citiesData = $overpass->query(sprintf('relation[admin_level=8][boundary=administrative]["ref:INSEE"](%f,%f,%f,%f);', $minLat, $minLon, $maxLat, $maxLon));
|
|
$citiesOsm = \OSM\OSM::createFromJson($citiesData);
|
|
$cities = [];
|
|
foreach ($citiesOsm->elements as $cityOsm) {
|
|
$geojson = \OSM\GeoJsonConverter::convertRelationToPolygon($cityOsm);
|
|
$geojsonString = '{"type":"FeatureCollection","features":[{"type": "Feature","properties":{},"geometry":'.json_encode($geojson->jsonSerialize()).'}]}';
|
|
$polygon = \geoPHP::load($geojsonString, 'json');
|
|
$cities[] = [
|
|
'name' => $cityOsm->getTagValue('name'),
|
|
'polygon' => $polygon,
|
|
'geojson' => $geojsonString,
|
|
'features' => [],
|
|
];
|
|
}
|
|
|
|
foreach ($issuesGeojson->getFeatures() as $feature) {
|
|
$point = \geoPHP::load(json_encode($feature->jsonSerialize()), 'json');
|
|
foreach ($cities as $cityIndex => $city) {
|
|
$isIn = $city['polygon']->contains($point);
|
|
if ($isIn) {
|
|
$cities[$cityIndex]['features'][] = $feature;
|
|
}
|
|
}
|
|
}
|
|
|
|
$cities = array_filter($cities, function ($city) { return !empty($city['features']); });
|
|
|
|
$response->setCallback(function () use ($cities): void {
|
|
$headings = [
|
|
'name',
|
|
'description',
|
|
'osm',
|
|
'geojson',
|
|
'status',
|
|
];
|
|
|
|
$csv = fopen('php://output', 'a');
|
|
|
|
fputcsv($csv, $headings);
|
|
|
|
foreach ($cities as $city) {
|
|
$name = $city['name'];
|
|
$description = sprintf('**%d** signalements sur la commune **%s** :'.PHP_EOL.PHP_EOL, count($city['features']), $city['name']);
|
|
$geojson = $city['geojson'];
|
|
|
|
$nodes = [];
|
|
foreach ($city['features'] as $featureIndex => $feature) {
|
|
$properties = $feature->getProperties();
|
|
$description .= sprintf('* Signalement %s %s'.PHP_EOL, $properties['uuid'], $properties['title']);
|
|
|
|
if (isset($properties['fixes'])) {
|
|
$tags = [];
|
|
foreach ($properties['fixes'] as $fixItems) {
|
|
foreach ($fixItems as $fixItem) {
|
|
$isExpected = (
|
|
('N' === $fixItem['type'])
|
|
and array_key_exists('create', $fixItem)
|
|
);
|
|
if (!$isExpected) {
|
|
continue;
|
|
} // TODO gérer tous les cas possibles ici
|
|
foreach ($fixItem['create'] as $k => $v) {
|
|
$tags[$k] = $v;
|
|
}
|
|
}
|
|
}
|
|
|
|
$geometry = $feature->getGeometry();
|
|
$coordinates = $geometry->getCoordinates();
|
|
$nodes[] = [
|
|
'type' => 'node',
|
|
'id' => -1 * ($featureIndex + 1),
|
|
'lat' => (float) $coordinates[1],
|
|
'lon' => (float) $coordinates[0],
|
|
'tags' => $tags,
|
|
];
|
|
}
|
|
}
|
|
if (!empty($nodes)) {
|
|
$osm = \OSM\OSM::createFromArray([
|
|
'elements' => $nodes,
|
|
]);
|
|
} else {
|
|
$osm = '';
|
|
}
|
|
|
|
fputcsv($csv, [
|
|
$name,
|
|
$description,
|
|
$osm,
|
|
$geojson,
|
|
'todo',
|
|
]);
|
|
}
|
|
|
|
fclose($csv);
|
|
});
|
|
} else {
|
|
$response->setCallback(function () use ($issuesGeojson): void {
|
|
$headings = [
|
|
'name',
|
|
'description',
|
|
'osm',
|
|
'geojson',
|
|
'status',
|
|
];
|
|
|
|
$csv = fopen('php://output', 'a');
|
|
|
|
fputcsv($csv, $headings);
|
|
|
|
$total = $issuesGeojson->count();
|
|
foreach ($issuesGeojson->getFeatures() as $index => $feature) {
|
|
$properties = $feature->getProperties();
|
|
$name = sprintf('%s n°%d/%d', $properties['title'], $index + 1, $total);
|
|
$description = <<<EOT
|
|
### Signalement {$properties['uuid']}
|
|
|
|
* Niveau {$properties['level']}
|
|
* Thème {$properties['item']}
|
|
* Identifiant de source {$properties['source_id']}
|
|
* Identifiant de classe {$properties['class']}
|
|
|
|
### Osmose
|
|
|
|
[✔ Fait](https://osmose.openstreetmap.fr/api/0.3/issue/{$properties['uuid']}/done)
|
|
[✘ Faux positif](https://osmose.openstreetmap.fr/api/0.3/issue/{$properties['uuid']}/false)
|
|
EOT;
|
|
if (isset($properties['fixes'])) {
|
|
$tags = [];
|
|
foreach ($properties['fixes'] as $fixItems) {
|
|
foreach ($fixItems as $fixItem) {
|
|
$isExpected = (
|
|
('N' === $fixItem['type'])
|
|
and array_key_exists('create', $fixItem)
|
|
);
|
|
if (!$isExpected) {
|
|
continue;
|
|
} // TODO gérer tous les cas possibles ici
|
|
foreach ($fixItem['create'] as $k => $v) {
|
|
$tags[$k] = $v;
|
|
}
|
|
}
|
|
}
|
|
|
|
$geometry = $feature->getGeometry();
|
|
$coordinates = $geometry->getCoordinates();
|
|
$osm = \OSM\OSM::createFromArray([
|
|
'elements' => [[
|
|
'type' => 'node',
|
|
'id' => -1,
|
|
'lat' => (float) $coordinates[1],
|
|
'lon' => (float) $coordinates[0],
|
|
'tags' => $tags,
|
|
]],
|
|
]);
|
|
} else {
|
|
$osm = '';
|
|
}
|
|
|
|
fputcsv($csv, [
|
|
$name,
|
|
$description,
|
|
$osm,
|
|
json_encode($feature->jsonSerialize()),
|
|
'todo',
|
|
]);
|
|
}
|
|
|
|
fclose($csv);
|
|
});
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
return $this->render('tools/osmose.html.twig', [
|
|
'form' => $form,
|
|
]);
|
|
}
|
|
}
|