sorry I ask chatGPT to make hexagons size constant, this is its code :
I precise that I ask it to make circles and squares too
backend :

<?php

header('Content-Type: application/json');



// Connexion Redis

$redis = new Redis();

$redis->connect('127.0.0.1', 6379);

$redis->auth('your_strong_password');



// Connexion PostgreSQL

$pdo = new PDO("pgsql:host=localhost;dbname=database", "user", "password", [

    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,

]);



$shape = $_GET['shape'] ?? 'hexagone';

$bbox = explode(',', $_GET['bbox']);

$size = $_GET['size'] ?? 1000;

$radius = $_GET['radius'] ?? 500;

$resolution = $_GET['resolution'] ?? 8;

$zoom = $_GET['zoom'] ?? 2;



$cacheKey = "$shape:" . implode('-', $bbox) .
":$size:$radius:$resolution:$zoom";



// Vérifier le cache Redis

if ($redis->exists($cacheKey)) {

    echo $redis->get($cacheKey);

    exit;

}



list($minLng, $minLat, $maxLng, $maxLat) = $bbox;

$params = [':minLng' => $minLng, ':minLat' => $minLat, ':maxLng' =>
$maxLng, ':maxLat' => $maxLat];



if ($shape === "hexagone") {

    $sql = "

        SELECT h3_geo_to_h3(ST_Y(geom), ST_X(geom), :resolution) AS
h3_cell, COUNT(*) AS point_count

        FROM your_points_table

        WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
4326)

        GROUP BY h3_cell;

    ";

    $params[':resolution'] = $resolution;

} elseif ($shape === "cercle") {

    $sql = "

        SELECT ST_AsGeoJSON(ST_Buffer(geom::geography, :radius)::geometry)
AS shape, COUNT(*) AS point_count

        FROM your_points_table

        WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
4326)

        GROUP BY shape;

    ";

    $params[':radius'] = $radius;

} else {

    $sql = "

        SELECT ST_AsGeoJSON(ST_Envelope(ST_Buffer(geom::geography, :size,
'quad_segs=1')::geometry)) AS shape, COUNT(*) AS point_count

        FROM your_points_table

        WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
4326)

        GROUP BY shape;

    ";

    $params[':size'] = $size;

}



$stmt = $pdo->prepare($sql);

$stmt->execute($params);

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);



// Mise en cache Redis (10 minutes)

$redis->setEx($cacheKey, 600, json_encode($result));



echo json_encode($result);


frontend :

<!DOCTYPE html>

<html lang="fr">

<head>

    <meta charset="UTF-8">

    <title>Cartographie Dynamique (PHP + jQuery)</title>

    <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css
">

    <script src="https://unpkg.com/leaflet/dist/leaflet.js";></script>

    <script src="https://code.jquery.com/jquery-3.6.0.min.js";></script>

    <style>

        #map { height: 500px; width: 100%; }

    </style>

</head>

<body>



<h2>Choisissez la forme :</h2>

<select id="shapeSelector">

    <option value="hexagone">Hexagone</option>

    <option value="cercle">Cercle</option>

    <option value="carre">Carré</option>

</select>



<div id="map"></div>



<script>

    const map = L.map('map').setView([0, 0], 2);

    L.tileLayer('https://{s}.
tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);



    let layer;

    let currentShape = 'hexagone';



    function getColor(count) {

        return count > 100 ? '#800026' :

               count > 50  ? '#BD0026' :

               count > 20  ? '#E31A1C' :

               count > 10  ? '#FC4E2A' :

                             '#FFEDA0';

    }



    function fetchData() {

        const bounds = map.getBounds();

        const bbox =
`${bounds.getWest()},${bounds.getSouth()},${bounds.getEast()},${bounds.getNorth()}`;

        const zoom = map.getZoom();




$.getJSON(`backend.php?shape=${currentShape}&bbox=${bbox}&size=1000&radius=500&resolution=8&zoom=${zoom}`,
function (data) {

            if (layer) map.removeLayer(layer);



            layer = L.geoJSON(data.map(item => JSON.parse(item.shape ||
item.h3_cell)), {

                style: (feature) => ({

                    color: getColor(feature.properties?.point_count || 0),

                    weight: 2,

                    fillOpacity: 0.5

                })

            }).addTo(map);

        });

    }



    $("#shapeSelector").change(function () {

        currentShape = $(this).val();

        fetchData();

    });



    map.on('moveend zoomend', fetchData);

    fetchData();

</script>



</body>

</html>

------------------------------


Sylvain Ard
0549507724
0778380991
sylvain....@gmail.com
https://www.sylvain-ard.fr <http://sylvain-ard.fr>
Entreprise individuelle SIRET : 80079243400022
Appt 26 Bât A Résidence Le Patio
83 rue de la Bugellerie
86000 Poitiers


Le ven. 14 mars 2025 à 20:59, Sylvain Ard <sylvain....@gmail.com> a écrit :

> this is the code of chatGPT with H3 :
> backend :
>
> <?php
>
> header('Content-Type: application/json');
>
>
>
> $pdo = new PDO("pgsql:host=localhost;dbname=database", "user", "password",
> [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
>
> $redis = new Redis();
>
> $redis->connect('127.0.0.1', 6379);
>
> $redis->auth('password');
>
>
>
> $shape = $_GET['shape'];
>
> $bbox = explode(',', $_GET['bbox']);
>
> $size = $_GET['size'] ?? null;
>
> $radius = $_GET['radius'] ?? null;
>
> $resolution = $_GET['resolution'] ?? 8;
>
>
>
> $cacheKey = "$shape:" . implode('-', $bbox) . ":$size:$radius:$resolution";
>
>
>
> if ($redis->exists($cacheKey)) {
>
>     echo $redis->get($cacheKey);
>
>     exit;
>
> }
>
>
>
> if ($shape === "hexagone") {
>
>     $sql = "
>
>         SELECT h3_geo_to_h3(ST_Y(geom), ST_X(geom), :resolution) AS
> h3_cell, COUNT(*) AS point_count
>
>         FROM your_points_table
>
>         WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
> 4326)
>
>         GROUP BY h3_cell;
>
>     ";
>
>     $params = [':resolution' => $resolution, ':minLng' => $bbox[0],
> ':minLat' => $bbox[1], ':maxLng' => $bbox[2], ':maxLat' => $bbox[3]];
>
> } elseif ($shape === "cercle") {
>
>     $sql = "
>
>         SELECT ST_AsGeoJSON(ST_Buffer(geom::geography, :radius)::geometry)
> AS shape, COUNT(*) AS point_count
>
>         FROM your_points_table
>
>         WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
> 4326)
>
>         GROUP BY shape;
>
>     ";
>
>     $params = [':radius' => $radius, ':minLng' => $bbox[0], ':minLat' =>
> $bbox[1], ':maxLng' => $bbox[2], ':maxLat' => $bbox[3]];
>
> } else {
>
>     $sql = "
>
>         SELECT ST_AsGeoJSON(ST_Envelope(ST_Buffer(geom::geography, :size,
> 'quad_segs=1')::geometry)) AS shape, COUNT(*) AS point_count
>
>         FROM your_points_table
>
>         WHERE geom && ST_MakeEnvelope(:minLng, :minLat, :maxLng, :maxLat,
> 4326)
>
>         GROUP BY shape;
>
>     ";
>
>     $params = [':size' => $size, ':minLng' => $bbox[0], ':minLat' =>
> $bbox[1], ':maxLng' => $bbox[2], ':maxLat' => $bbox[3]];
>
> }
>
>
>
> $stmt = $pdo->prepare($sql);
>
> $stmt->execute($params);
>
> $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
>
>
>
> $redis->setEx($cacheKey, 3600, json_encode($result));
>
> echo json_encode($result);
>
>
> frontend :
>
>
> <!DOCTYPE html>
>
> <html lang="fr">
>
> <head>
>
>     <meta charset="UTF-8">
>
>     <title>Cartographie avec Forme Sélectionnée</title>
>
>     <link rel="stylesheet" href="
> https://unpkg.com/leaflet/dist/leaflet.css";>
>
>     <script src="https://unpkg.com/leaflet/dist/leaflet.js";></script>
>
>     <script src="https://code.jquery.com/jquery-3.6.0.min.js";></script>
>
>     <style>
>
>         #map { height: 500px; width: 100%; }
>
>     </style>
>
> </head>
>
> <body>
>
>
>
> <h2>Choisissez la forme :</h2>
>
> <select id="shapeSelector">
>
>     <option value="hexagone">Hexagone</option>
>
>     <option value="cercle">Cercle</option>
>
>     <option value="carre">Carré</option>
>
> </select>
>
>
>
> <div id="map"></div>
>
>
>
> <script>
>
>     const map = L.map('map').setView([0, 0], 2);
>
>     L.tileLayer('https://{s}.
> tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map
> <http://tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png').addTo(map>);
>
>
>
>     let layer;
>
>
>
>     function fetchData(shape) {
>
>         const bbox = "-10,-10,10,10";
>
>         const url =
> `backend.php?shape=${shape}&bbox=${bbox}&size=1000&radius=500&resolution=8`;
>
>
>
>         $.getJSON(url, function (data) {
>
>             if (layer) map.removeLayer(layer);
>
>             layer = L.geoJSON(data, {
>
>                 style: {
>
>                     color: shape === "carre" ? "green" : shape ===
> "cercle" ? "blue" : "red",
>
>                     weight: 2,
>
>                     fillOpacity: 0.4
>
>                 }
>
>             }).addTo(map);
>
>         });
>
>     }
>
>
>
>     $("#shapeSelector").change(function () {
>
>         fetchData($(this).val());
>
>     });
>
>
>
>     fetchData("hexagone"); // Chargement initial
>
> </script>
>
>
>
> </body>
>
> </html>
>
> Sylvain Ard
> 0549507724
> 0778380991
> sylvain....@gmail.com
> https://www.sylvain-ard.fr <http://sylvain-ard.fr>
> Entreprise individuelle SIRET : 80079243400022
> Appt 26 Bât A Résidence Le Patio
> 83 rue de la Bugellerie
> 86000 Poitiers
>
>
> Le ven. 14 mars 2025 à 20:49, Sylvain Ard <sylvain....@gmail.com> a
> écrit :
>
>> yes but H3 can't simplify the job ?
>> Sylvain Ard
>> 0549507724
>> 0778380991
>> sylvain....@gmail.com
>> https://www.sylvain-ard.fr <http://sylvain-ard.fr>
>> Entreprise individuelle SIRET : 80079243400022
>> Appt 26 Bât A Résidence Le Patio
>> 83 rue de la Bugellerie
>> 86000 Poitiers
>>
>>
>> Le ven. 14 mars 2025 à 20:48, Brent Wood <brent.w...@niwa.co.nz> a
>> écrit :
>>
>>> Hi,
>>>
>>> Off the top of my head...
>>>
>>> Postgis can easily cope with millions of records. Given the points are
>>> there, use that to create the hexagons as required - this can be done using
>>> https://postgis.net/docs/ST_HexagonGrid.html
>>>
>>> If you set up your QGIS project with preset zoom levels, and create a
>>> set of appropriately sized hexagons for each zoom level, then populate a
>>> column with the number of points it contains.
>>>
>>> There will be some devilish details - as you zoom in, the polygon's real
>>> area will get smaller, so will contain less points. A fixed symbology will
>>> therefore change the colour range with the scale.
>>>
>>> Calculating a normalised value, perhaps something like instead of the no
>>> of points, you calculate a normalised value - the hex at each scale with
>>> the most points gets 100, the rest get a value based on the no of
>>> points/the max for that scale, so all polygon datasets will have colours
>>> set to values between 0 and 100. All doable with SQL.
>>>
>>> Do all the data stuff in Postgis, then just plot in QGIS.
>>>
>>> There are various ways to set QGIS up for this, but one reasonably
>>> straightforward way that should work is having a separate hexagon layer for
>>> each scale, with a scale limit on displaying it so that all map scales are
>>> represented by one of the hexagon layers, with the fixed zoom
>>> levels/scales, set the same symbology for each layer, then  group them into
>>> a single group.
>>>
>>>
>>> Something to consider anyway...
>>>
>>> Cheers
>>>
>>> Brent Wood
>>>
>>> Principal Technician, Fisheries
>>> NIWA
>>> DDI:  +64 (4) 3860529
>>> ------------------------------
>>> *From:* QGIS-User <qgis-user-boun...@lists.osgeo.org> on behalf of
>>> Sylvain Ard via QGIS-User <qgis-user@lists.osgeo.org>
>>> *Sent:* Friday, March 14, 2025 23:35
>>> *To:* qgis-user@lists.osgeo.org <qgis-user@lists.osgeo.org>
>>> *Subject:* [Qgis-user] question
>>>
>>> Hello,
>>> I'd like a map with hexagons that are darker the more points there are
>>> underneath. My points are in a PostgreSQL table. If there are no points,
>>> there should be no hexagon. The hexagons have a constant size on the
>>> screen, so they have to be recalculated each time the map is zoomed in. I
>>> want a truly optimized solution because I have millions of points. So,
>>> perhaps I could use QGIS-server.
>>> Please suggest a solution for both the server and client side.
>>> Best regards
>>> PS : my map must be like GBIF maps
>>>
>>> Sylvain Ard
>>> 0549507724
>>> 0778380991
>>> sylvain....@gmail.com
>>> https://www.sylvain-ard.fr <http://sylvain-ard.fr/>
>>> Entreprise individuelle SIRET : 80079243400022
>>> Appt 26 Bât A Résidence Le Patio
>>> 83 rue de la Bugellerie
>>> 86000 Poitiers
>>> <https://www.niwa.co.nz/>
>>> Brent Wood
>>> Principal Technician - GIS and Spatial Data Management
>>> Programme Leader - Environmental Information Delivery
>>> +64-4-386-0529
>>>
>>> National Institute of Water & Atmospheric Research Ltd (NIWA)
>>> 301 Evans Bay Parade Hataitai Wellington New Zealand
>>> *Connect with NIWA:* niwa.co.nz <https://www.niwa.co.nz/> Facebook
>>> <https://www.facebook.com/nzniwa> LinkedIn
>>> <https://www.linkedin.com/company/niwa> Twitter
>>> <https://twitter.com/niwa_nz> Instagram
>>> <https://www.instagram.com/niwa_science> YouTube
>>> <https://www.youtube.com/channel/UCJ-j3MLMg1H59Ak2UaNLL3A> To ensure
>>> compliance with legal requirements and to maintain cyber security
>>> standards, NIWA's IT systems are subject to ongoing monitoring, activity
>>> logging and auditing. This monitoring and auditing service may be provided
>>> by third parties. Such third parties can access information transmitted to,
>>> processed by and stored on NIWA's IT systems.
>>> Note: This email is intended solely for the use of the addressee and may
>>> contain information that is confidential or subject to legal professional
>>> privilege. If you receive this email in error please immediately notify the
>>> sender and delete the email.
>>>
>>
_______________________________________________
QGIS-User mailing list
QGIS-User@lists.osgeo.org
List info: https://lists.osgeo.org/mailman/listinfo/qgis-user
Unsubscribe: https://lists.osgeo.org/mailman/listinfo/qgis-user

Reply via email to