Skip to content

Instantly share code, notes, and snippets.

@deton
Last active January 5, 2025 12:00
Show Gist options
  • Save deton/0cf7888070fcb801e1fd5aaa6f1cc6e2 to your computer and use it in GitHub Desktop.
Save deton/0cf7888070fcb801e1fd5aaa6f1cc6e2 to your computer and use it in GitHub Desktop.
OSMGraphPoints class to get random points on the road network obtained with https://github.com/deton/GraphFromOSM
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>GraphFromOSM and sample random points</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""/>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jonatanheyman/[email protected]/src/leaflet-areaselect.css"/>
<script src="https://cdn.jsdelivr.net/npm/@jonatanheyman/[email protected]/src/leaflet-areaselect.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css" />
<script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
<style type="text/css">
body {
padding: 0;
margin: 0;
}
#map {
width: 100%;
height: 100vh;
}
#toolbar {
position: absolute;
top: 5px;
left: 60px;
z-index: 1000;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="toolbar" class="leaflet-control">
<button id="randomPointsButton" onclick="randomPoints()">Random Points</button>
</div>
<script type="importmap">
{
"imports": {
"osm-graph-points": "./osm-graph-points.js",
"@turf/bbox-polygon": "https://cdn.jsdelivr.net/npm/@turf/[email protected]/+esm",
"@turf/points-within-polygon": "https://cdn.jsdelivr.net/npm/@turf/[email protected]/+esm",
"@turf/sample": "https://cdn.jsdelivr.net/npm/@turf/[email protected]/+esm",
"graph-from-osm": "https://deton.github.io/GraphFromOSM/graph-from-osm.js"
}
}
</script>
<script type="module">
import { OSMGraphPoints } from "osm-graph-points";
let osmGraphPoints = new OSMGraphPoints(bounds2bbox(bounds));
let geojsonLayer;
function bounds2bbox(b) {
return [b.getWest(), b.getSouth(), b.getEast(), b.getNorth()];
}
async function randomPoints() {
const boundsnew = areaSelect.getBounds();
if (!boundsnew.equals(bounds)) {
bounds = boundsnew;
console.log(`bbox=${bounds.toBBoxString()}`);
osmGraphPoints = new OSMGraphPoints(bounds2bbox(bounds));
}
const points = await osmGraphPoints.samplePoints(10);
if (geojsonLayer) {
geojsonLayer.remove();
}
geojsonLayer = L.geoJSON(points).bindPopup(layer => {
return JSON.stringify(layer.feature.properties);
}).addTo(map);
}
window.randomPoints = randomPoints;
</script>
<script>
var map = L.map('map');
L.tileLayer('https://tile.openstreetmap.jp/styles/osm-bright/{z}/{x}/{y}.png', {
attribution: '<a href="https://www.openmaptiles.org/" target="_blank">&copy; OpenMapTiles</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a>'
}).addTo(map);
const urlParams = new URLSearchParams(document.location.search);
// bbox=<westLng>,<southLat>,<eastLng>,<northLat>
let bboxParam = urlParams.get('bbox') || '139.7688,35.6970,139.7761,35.7031';
let [west, south, east, north] = bboxParam.split(',').map(Number);
var bounds = L.latLngBounds([[south, west], [north, east]]);
var areaSelect = L.areaSelect().addTo(map);
areaSelect.setBounds(bounds);
L.Control.geocoder({
defaultMarkGeocode: false
}).on('markgeocode', ev => {
map.panTo(ev.geocode.center);
}).addTo(map);
</script>
</body>
</html>
import { parseArgs } from "node:util";
import { OSMGraphPoints } from "./osm-graph-points.js";
const { positionals } = parseArgs({ allowPositionals: true });
let bbox = positionals[0] || "139.7688,35.6970,139.7761,35.7031";
console.log("bbox", bbox);
let osmGraphPoints = new OSMGraphPoints(bbox.split(",").map(Number));
osmGraphPoints.samplePoints(10).then(points => {
console.log(JSON.stringify(points));
}).catch(console.error);
import GraphFromOSM from "graph-from-osm";
import { bboxPolygon } from "@turf/bbox-polygon";
import { pointsWithinPolygon } from "@turf/points-within-polygon";
import { sample } from "@turf/sample";
export class OSMGraphPoints {
bbox;
osmPoints;
graphFromOSMSettings;
constructor(bbox, settings = {"highways": "ALL", "timeout": 10000, "maxContentLength": 10737418}) {
this.bbox = bbox;
this.graphFromOSMSettings = {
"bbox": bbox,
...settings,
};
}
async graphFromOSM() {
const data = await GraphFromOSM.getOsmData(this.graphFromOSMSettings);
return GraphFromOSM.osmDataToGraph(data);
}
async samplePoints(num, bboxFilter = undefined) {
if (this.osmPoints === undefined) {
const networkjson = await this.graphFromOSM();
// XXX: Points may not on road network
const points = networkjson.features.filter(f => f.geometry.type === "Point");
const pointsfc = {type: "FeatureCollection", features: points};
const poly = bboxPolygon(this.bbox);
this.osmPoints = pointsWithinPolygon(pointsfc, poly);
}
if (bboxFilter) {
const filtPoly = bboxPolygon(bboxFilter);
const filtPoints = pointsWithinPolygon(this.osmPoints, filtPoly);
return sample(filtPoints, num);
}
return sample(this.osmPoints, num);
}
}
{
"name": "osm-graph-points",
"version": "1.0.0",
"type": "module",
"exports": "./osm-graph-points.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "KIHARA, Hideto",
"license": "MIT",
"description": "Get random points on the road network obtained with GraphFromOSM",
"dependencies": {
"@turf/bbox-polygon": "^7.2.0",
"@turf/points-within-polygon": "^7.2.0",
"@turf/sample": "^7.2.0",
"graph-from-osm": "github:deton/GraphFromOSM"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment