diff --git a/lib/OSM/Element/Member/Relation.php b/lib/OSM/Element/Member/Relation.php new file mode 100644 index 0000000..0242e4a --- /dev/null +++ b/lib/OSM/Element/Member/Relation.php @@ -0,0 +1,14 @@ +createForm(OsmoseToolType::class, $request->query->all()); + $form = $this->createForm(OsmoseToolType::class, array_merge(['limit' => 500], $request->query->all())); $form->add('submit', SubmitType::class, ['label' => 'Générer']); $form->handleRequest($request); @@ -106,10 +107,10 @@ class ToolsController extends AbstractController 'item' => $form->get('item')->getData(), 'source' => $form->get('source')->getData(), 'class' => $form->get('class')->getData(), + 'limit' => $form->get('limit')->getData(), 'username' => '', 'bbox' => '', 'full' => 'true', - 'limit' => 500, ]); $response = new StreamedResponse(); @@ -123,85 +124,206 @@ class ToolsController extends AbstractController ) ); - $features = json_decode($issues, true)['features']; + $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; + } + } - $response->setCallback(function () use ($features): void { - $headings = [ - 'name', - 'description', - 'osm', - 'geojson', - 'status', - ]; + $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' => [], + ]; + } - $csv = fopen('php://output', 'a'); + 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; + } + } + } - fputcsv($csv, $headings); + $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; + } + } + } - $total = count($features); - foreach ($features as $index => $feature) { - $name = sprintf('%s n°%d/%d', $feature['properties']['title'], $index + 1, $total); - $description = <<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 = ''; + } -* Level {$feature['properties']['level']} -* Item {$feature['properties']['item']} -* Identifiant de source {$feature['properties']['source_id']} -* Identifiant de classe {$feature['properties']['class']} + 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 = << $v) { - $tags[$k] = $v; + 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 = ''; } - $osm = \OSM\OSM::createFromArray([ - 'elements' => [[ - 'type' => 'node', - 'id' => -1, - 'lat' => (float) $feature['geometry']['coordinates'][1], - 'lon' => (float) $feature['geometry']['coordinates'][0], - 'tags' => $tags, - ]], + fputcsv($csv, [ + $name, + $description, + $osm, + json_encode($feature->jsonSerialize()), + 'todo', ]); - } else { - $osm = ''; } - $geojson = json_encode([ - 'type' => 'FeatureCollection', - 'features' => [ - $feature, - ], - ]); - - fputcsv($csv, [ - $name, - $description, - $osm, - $geojson, - 'todo', - ]); - } - - fclose($csv); - }); + fclose($csv); + }); + } return $response; } diff --git a/src/Form/OsmoseToolType.php b/src/Form/OsmoseToolType.php index 7789dae..4ee93d4 100644 --- a/src/Form/OsmoseToolType.php +++ b/src/Form/OsmoseToolType.php @@ -3,6 +3,7 @@ namespace App\Form; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\FormBuilderInterface; @@ -13,6 +14,8 @@ class OsmoseToolType extends AbstractType $builder ->add('item', IntegerType::class, [ 'label' => 'Item', + 'help_html' => true, + 'help' => 'Voir la liste sur le wiki', ]) ->add('source', IntegerType::class, [ 'label' => 'Identifiant source', @@ -20,6 +23,14 @@ class OsmoseToolType extends AbstractType ->add('class', IntegerType::class, [ 'label' => 'Identifiant de la classe', ]) + ->add('limit', IntegerType::class, [ + 'label' => 'Limite', + 'help' => 'Nombre mmaximal de signalements à renvoyer', + ]) + ->add('group_by_city', CheckboxType::class, [ + 'label' => 'Grouper par commune', + 'required' => false, + ]) ; } }