From 6523bdf4c00e7d429787ce8de086752ba53ad72c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB?= Date: Fri, 15 Mar 2024 23:48:14 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BC=D0=B5=D0=BD=D0=B0=20=D1=81=D1=82?= =?UTF-8?q?=D0=B8=D0=BB=D1=8F=20=D0=BC=D0=B0=D1=82=D0=BE=D1=87=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BF=D0=BB=D0=BE=D1=89=D0=B0=D0=B4=D0=BE=D0=BA,=20?= =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0=20Overpass=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- expl.html | 6 +- explication.js | 275 +++++++----------------------------------- explication_blocks.js | 7 +- js/OsmGeoDocLib.js | 190 ++++++++++++++++++++++++++++- 4 files changed, 243 insertions(+), 235 deletions(-) diff --git a/expl.html b/expl.html index 5405edb..8d3f040 100644 --- a/expl.html +++ b/expl.html @@ -365,10 +365,11 @@

Фонари

Экспорт данных } function subAreaFilter(xhr) { - log('Внутренние данные получены '); + log('Внутренние данные парка получены, выделяем участки '); var xml = xhr.responseXML; // Выделяем участки парка - var osm_id_участки = xhr.ini_obj.osm_obj_type == 'relation' ? this.OsmGDlib.getSubAreas(xml, xhr.ini_obj.osm_obj_id) : null; + var main_id = xhr.ini_obj.osm_obj_id; + var osm_id_участки = xhr.ini_obj.osm_obj_type == 'relation' ? this.OsmGDlib.getSubAreas(xhr.ini_obj.osm_main_obj_xml, main_id) : null; this.geoJsonGeneral = osmtogeojson(xml); var участки = []; for (var i in osm_id_участки) { @@ -378,7 +379,6 @@

Фонари

Экспорт данных gJ.bbox = this.OsmGDlib.γεωμετρία.bbox(gJ); участки.push(gJ); } - log('Участки выделены '); var el = decodeURI(location.hash).replace('#', '').split(';'); var filter = el[1] ? el[1] : null; diff --git a/explication.js b/explication.js index 0467f29..1d6349b 100644 --- a/explication.js +++ b/explication.js @@ -41,22 +41,25 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ }; L.OSM.park_explication.prototype.getAllgeoData = function (osm_main_obj_xml) { - var mr = (this.osm_obj_type == 'relation') ? this.OsmGDlib.osmRelationGeoJson(osm_main_obj_xml, this.osm_obj_id) : ((this.osm_obj_type == 'way') ? this.OsmGDlib.osmWayGeoJson(osm_main_obj_xml, this.osm_obj_id) : null); - var t = mr.tags; + this.osm_main_obj_xml = osm_main_obj_xml; + var main_rel = (this.osm_obj_type == 'relation') ? this.OsmGDlib.osmRelationGeoJson(osm_main_obj_xml, this.osm_obj_id) : ((this.osm_obj_type == 'way') ? this.OsmGDlib.osmWayGeoJson(osm_main_obj_xml, this.osm_obj_id) : null); + if (!main_rel) + { + alert("Основной объект OSM не указан"); + return; + } + this.main_rel = main_rel.features[0]; + var t = this.main_rel.tags; if (t && t.wikidata) { var wikiDataQ = t.wikidata; log('OSM: WikiData - ' + wikiDataQ); } - var gJs = L.geoJSON(mr); + if (this.getWikiData) this.getWikiData(t ? t.wikidata : null); - var b = gJs.getBounds(); - console.log(b, gJs, this.osm_obj_type); - var xhr = new XMLHttpRequest(); - xhr.url = "https://overpass-api.de/api/interpreter?data=[out:xml];(++node(" + b.getSouth() + "," + b.getWest() + "," + b.getNorth() + "," + b.getEast() + ");<;);(._;>;);out+meta;"; - // 'https://www.openstreetmap.org/api/0.6/map?bbox=' + gJs.getBounds().toBBoxString(); + xhr.url = 'https://overpass-api.de/api/interpreter?data=[out:xml];( relation(' + this.osm_obj_id +'););map_to_area;(nwr(area);>;);out+meta;'; xhr.open('GET', xhr.url, true); xhr.ini_obj = this; xhr.send(); @@ -70,6 +73,7 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ } } }; + L.OSM.park_explication.prototype.get_data = function () { var xhr = new XMLHttpRequest(); xhr.url = this.OsmGDlib.OSM_URL(this.osm_obj_type, this.osm_obj_id, 'full'); @@ -91,8 +95,7 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ }; L.OSM.park_explication.prototype.map = function (div, map_prov, map_params) { - var mrg = this.general_rel_geoJson(this.geoJsonGeneral); - var cen = turf_centroid(mrg); + var cen = this.OsmGDlib.γεωμετρία.centroid(this.main_rel); var md = new mapDiv( div, cen, @@ -107,8 +110,8 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ map_params ); - var n = mrg.properties.tags.name; - var mr = L.geoJSON(mrg, { fillOpacity: 0, color: "#F2872F" }); + var n = this.main_rel.properties.tags.name; + var mr = L.geoJSON(this.main_rel, { fillOpacity: 0, color: "#F2872F" }); md.map.fitBounds(mr.getBounds()); md.Control.addOverlay(mr, n); md.map.addLayer(mr); @@ -129,14 +132,12 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ map_params, explicationDataProcess ) { - log('Получены исходные данные '); + log('Данные по участкам переданы, фильтруем по датам '); var hronofiltr = map_params.start_date ?? null; - var main_rel = this.general_rel_geoJson(); - document.getElementById('obj_title').innerText = main_rel.properties.tags.name + (map_params.start_date ? (" (" + map_params.start_date + ")") : ""); - this.block = {}; - for (var oi in expl_func_blocks) { - this.block[oi] = new L.OSM.park_explication_block(expl_func_blocks[oi]); - } + //this.exportJSON(this.geoJsonGeneral, "1"); + console.log(Object.keys(this.geoJsonGeneral.features).length); + var del = []; + var main_bbox = this.OsmGDlib.γεωμετρία.bbox(this.main_rel); for (var i in this.geoJsonGeneral.features) { var osmGeoJSON_obj = this.geoJsonGeneral.features[i]; @@ -159,29 +160,30 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ } } if (max_date > hronofiltr) - continue; + del.push(i); console.log(min_date + " " + max_date + " " + osmGeoJSON_obj.properties.tags['start_date']); } +/* + var f_bbox = this.OsmGDlib.γεωμετρία.bbox(osmGeoJSON_obj); + if (! this.OsmGDlib.γεωμετρία.bboxIntersect(main_bbox, f_bbox)) + del.push(i);*/ + } + for (var i in del) + this.geoJsonGeneral.features.splice(i, 1); - var geoNd = this.OsmGDlib.γεωμετρία.geo_nodes(osmGeoJSON_obj); + log('Отфильтровано по времени появления ' + Object.keys(this.geoJsonGeneral.features).length + ' объектов, выявляем на каких участках объекты '); - var ok = false; - for (var j_n in geoNd) { - if (this.OsmGDlib.γεωμετρία.booleanPointInPolygon(geoNd[j_n], main_rel, { ignoreBoundary: true })); - { - ok = true; - break; - } - } - - function uniq(value, index, self) { - return self.indexOf(value) === index; - } + this.block = {}; + for (var oi in expl_func_blocks) { + this.block[oi] = new L.OSM.park_explication_block(expl_func_blocks[oi]); + } + for (var i in this.geoJsonGeneral.features) { + var osmGeoJSON_obj = this.geoJsonGeneral.features[i]; // Проход по всем блокам для фильтрации объекта и определения принадлежности к участку for (var oi in this.block) { block = this.block[oi]; - if (ok && block.f_obj.filter(this, osmGeoJSON_obj)) { + if (block.f_obj.filter(this, osmGeoJSON_obj)) { var eo = new L.OSM.park_explication_obj(); eo.geoJSON = osmGeoJSON_obj; eo.bbox = this.OsmGDlib.γεωμετρία.bbox(osmGeoJSON_obj); @@ -194,8 +196,9 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ // Предварительный проход for (var i_u in участки) { var polyg = участки[i_u]; - if (! this.OsmGDlib.γεωμετρία.bboxIntersect(polyg.bbox, eo.bbox)) - continue; +/* if (! this.OsmGDlib.γεωμετρία.bboxIntersect(polyg.bbox, eo.bbox)) + continue;*/ + var geoNd = this.OsmGDlib.γεωμετρία.geo_nodes(osmGeoJSON_obj); for (var i_n in geoNd) { if (this.OsmGDlib.γεωμετρία.booleanPointInPolygon( geoNd[i_n], @@ -205,9 +208,11 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ уч_geoJson.push(polyg); } } - var SPGJ = уч_geoJson.filter(uniq) + var SPGJ = уч_geoJson.filter( + function (value, index, self) { return self.indexOf(value) === index; } + ); eo.superPartGeoJSON = SPGJ; - var sP = (SPGJ.length == 1) ? superPart(SPGJ) : null; + sP = (SPGJ.length == 1) ? superPart(SPGJ) : null; } // Заполняем основные данные объекта var data = block.f_obj.data_object(this, osmGeoJSON_obj, sP); @@ -223,14 +228,14 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ } } } - log('Первичная фильтрация объектов завершена'); + log('Участки для объектов выяснены, проверяем принадлежность'); for (var i in участки) { var osmGeoJSON_obj = участки[i]; var geoNd = this.OsmGDlib.γεωμετρία.geo_nodes(osmGeoJSON_obj); var ok = false; for (var j_n in geoNd) { - ok = ok || (this.OsmGDlib.γεωμετρία.booleanPointInPolygon(geoNd[j_n], main_rel, { ignoreBoundary: true })); + ok = ok || (this.OsmGDlib.γεωμετρία.booleanPointInPolygon(geoNd[j_n], this.main_rel, { ignoreBoundary: true })); } block = this.block['Участки']; @@ -334,7 +339,7 @@ L.OSM.park_explication = function(osm_obj_type, osm_obj_id, f_fin_ok){ } log('Отрисовка данных подготовлена'); - if (main_rel.properties.tags.name == 'Бирюлёвский дендропарк'){ + if (this.main_rel.properties.tags.name == 'Бирюлёвский дендропарк'){ this.привязка_указателей(this.block); log('Маточные площадки привязаны к указателям'); } @@ -636,191 +641,3 @@ L.OSM.park_explication.prototype.привязка_указателей = functio o.webData.Тип_информации = '' + п + ''; } }; - -function turf_centroid(geojson) { - var xSum = 0; - var ySum = 0; - var len = 0; - turf_coordEach(geojson, function (coord) { - xSum += coord[0]; - ySum += coord[1]; - len++; - }, true); - return [ySum / len, xSum / len]; -} - -/** - * Iterate over coordinates in any GeoJSON object, similar to Array.forEach() - * - * @name coordEach - * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object - * @param {Function} callback a method that takes (currentCoord, coordIndex, featureIndex, multiFeatureIndex) - * @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration. - * @returns {void} - * @example - * var features = turf.featureCollection([ - * turf.point([26, 37], {"foo": "bar"}), - * turf.point([36, 53], {"hello": "world"}) - * ]); - * - * turf.coordEach(features, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) { - * //=currentCoord - * //=coordIndex - * //=featureIndex - * //=multiFeatureIndex - * //=geometryIndex - * }); - */ -function turf_coordEach(geojson, callback, excludeWrapCoord) { - // Handles null Geometry -- Skips this GeoJSON - if (geojson === null) return; - var j, - k, - l, - geometry, - stopG, - coords, - geometryMaybeCollection, - wrapShrink = 0, - coordIndex = 0, - isGeometryCollection, - type = geojson.type, - isFeatureCollection = type === "FeatureCollection", - isFeature = type === "Feature", - stop = isFeatureCollection ? geojson.features.length : 1; - - // This logic may look a little weird. The reason why it is that way - // is because it's trying to be fast. GeoJSON supports multiple kinds - // of objects at its root: FeatureCollection, Features, Geometries. - // This function has the responsibility of handling all of them, and that - // means that some of the `for` loops you see below actually just don't apply - // to certain inputs. For instance, if you give this just a - // Point geometry, then both loops are short-circuited and all we do - // is gradually rename the input until it's called 'geometry'. - // - // This also aims to allocate as few resources as possible: just a - // few numbers and booleans, rather than any temporary arrays as would - // be required with the normalization approach. - for (var featureIndex = 0; featureIndex < stop; featureIndex++) { - geometryMaybeCollection = isFeatureCollection - ? geojson.features[featureIndex].geometry - : isFeature - ? geojson.geometry - : geojson; - isGeometryCollection = geometryMaybeCollection - ? geometryMaybeCollection.type === "GeometryCollection" - : false; - stopG = isGeometryCollection - ? geometryMaybeCollection.geometries.length - : 1; - - for (var geomIndex = 0; geomIndex < stopG; geomIndex++) { - var multiFeatureIndex = 0; - var geometryIndex = 0; - geometry = isGeometryCollection - ? geometryMaybeCollection.geometries[geomIndex] - : geometryMaybeCollection; - - // Handles null Geometry -- Skips this geometry - if (geometry === null) continue; - coords = geometry.coordinates; - var geomType = geometry.type; - - wrapShrink = - excludeWrapCoord && - (geomType === "Polygon" || geomType === "MultiPolygon") - ? 1 - : 0; - - switch (geomType) { - case null: - break; - case "Point": - if ( - callback( - coords, - coordIndex, - featureIndex, - multiFeatureIndex, - geometryIndex - ) === false - ) - return false; - coordIndex++; - multiFeatureIndex++; - break; - case "LineString": - case "MultiPoint": - for (j = 0; j < coords.length; j++) { - if ( - callback( - coords[j], - coordIndex, - featureIndex, - multiFeatureIndex, - geometryIndex - ) === false - ) - return false; - coordIndex++; - if (geomType === "MultiPoint") multiFeatureIndex++; - } - if (geomType === "LineString") multiFeatureIndex++; - break; - case "Polygon": - case "MultiLineString": - for (j = 0; j < coords.length; j++) { - for (k = 0; k < coords[j].length - wrapShrink; k++) { - if ( - callback( - coords[j][k], - coordIndex, - featureIndex, - multiFeatureIndex, - geometryIndex - ) === false - ) - return false; - coordIndex++; - } - if (geomType === "MultiLineString") multiFeatureIndex++; - if (geomType === "Polygon") geometryIndex++; - } - if (geomType === "Polygon") multiFeatureIndex++; - break; - case "MultiPolygon": - for (j = 0; j < coords.length; j++) { - geometryIndex = 0; - for (k = 0; k < coords[j].length; k++) { - for (l = 0; l < coords[j][k].length - wrapShrink; l++) { - if ( - callback( - coords[j][k][l], - coordIndex, - featureIndex, - multiFeatureIndex, - geometryIndex - ) === false - ) - return false; - coordIndex++; - } - geometryIndex++; - } - multiFeatureIndex++; - } - break; - case "GeometryCollection": - for (j = 0; j < geometry.geometries.length; j++) - if ( - coordEach(geometry.geometries[j], callback, excludeWrapCoord) === - false - ) - return false; - break; - default: - throw new Error("Unknown Geometry Type"); - } - } - } -} diff --git a/explication_blocks.js b/explication_blocks.js index 3421726..2291159 100644 --- a/explication_blocks.js +++ b/explication_blocks.js @@ -187,13 +187,16 @@ expl_func_blocks = { }; }, geoJSON_style: function (base, osmGeoJSON_obj, маточная_площадка) { + var t = osmGeoJSON_obj.properties.tags; var S = {}; if (маточная_площадка.Тип == 'Кусты') S.weight = 1; else if (маточная_площадка.Тип == '?') S.weight = 2; - else + else if (t['leaf_cycle']) S.weight = 2; + else + S.weight = 1; var lc = osmGeoJSON_obj.properties.tags['leaf_cycle']; var lt = osmGeoJSON_obj.properties.tags['leaf_type']; @@ -532,7 +535,7 @@ expl_func_blocks = { S.color = '88ff00'; else if (пл.Тип == 'Собачья площадка') S.color = 'bbbbbb'; - S.dashArray = '2, 2'; + S.dashArray = '2, 2'; return S; }, sort: function (a, b) { diff --git a/js/OsmGeoDocLib.js b/js/OsmGeoDocLib.js index 9546314..9b46dd7 100644 --- a/js/OsmGeoDocLib.js +++ b/js/OsmGeoDocLib.js @@ -292,7 +292,7 @@ OsmGeoDocLib = function (OSM_baseURL, OSM_API_URL){ /** * Calculate the approximate area of the polygon were it projected onto - * the earth. Note that this area will be positive if ring is oriented + * the earth. Note that this area will be positive if ring is oriented * clockwise, otherwise it will be negative. * * Reference: @@ -529,7 +529,195 @@ OsmGeoDocLib = function (OSM_baseURL, OSM_API_URL){ const yOverlaps = b[1] <= a[3] && b[3] >= a[1]; const xOverlaps = b[0] <= a[2] && b[2] >= a[0]; return xOverlaps && yOverlaps; + }, + centroid: function (geojson) { + var xSum = 0; + var ySum = 0; + var len = 0; + this.turf_coordEach(geojson, function (coord) { + xSum += coord[0]; + ySum += coord[1]; + len++; + }, true); + return [ySum / len, xSum / len]; + }, + +/** + * Iterate over coordinates in any GeoJSON object, similar to Array.forEach() + * + * @name coordEach + * @param {FeatureCollection|Feature|Geometry} geojson any GeoJSON object + * @param {Function} callback a method that takes (currentCoord, coordIndex, featureIndex, multiFeatureIndex) + * @param {boolean} [excludeWrapCoord=false] whether or not to include the final coordinate of LinearRings that wraps the ring in its iteration. + * @returns {void} + * @example + * var features = turf.featureCollection([ + * turf.point([26, 37], {"foo": "bar"}), + * turf.point([36, 53], {"hello": "world"}) + * ]); + * + * turf.coordEach(features, function (currentCoord, coordIndex, featureIndex, multiFeatureIndex, geometryIndex) { + * //=currentCoord + * //=coordIndex + * //=featureIndex + * //=multiFeatureIndex + * //=geometryIndex + * }); + */ + turf_coordEach: function (geojson, callback, excludeWrapCoord) { + // Handles null Geometry -- Skips this GeoJSON + if (geojson === null) return; + var j, + k, + l, + geometry, + stopG, + coords, + geometryMaybeCollection, + wrapShrink = 0, + coordIndex = 0, + isGeometryCollection, + type = geojson.type, + isFeatureCollection = type === "FeatureCollection", + isFeature = type === "Feature", + stop = isFeatureCollection ? geojson.features.length : 1; + + // This logic may look a little weird. The reason why it is that way + // is because it's trying to be fast. GeoJSON supports multiple kinds + // of objects at its root: FeatureCollection, Features, Geometries. + // This function has the responsibility of handling all of them, and that + // means that some of the `for` loops you see below actually just don't apply + // to certain inputs. For instance, if you give this just a + // Point geometry, then both loops are short-circuited and all we do + // is gradually rename the input until it's called 'geometry'. + // + // This also aims to allocate as few resources as possible: just a + // few numbers and booleans, rather than any temporary arrays as would + // be required with the normalization approach. + for (var featureIndex = 0; featureIndex < stop; featureIndex++) { + geometryMaybeCollection = isFeatureCollection + ? geojson.features[featureIndex].geometry + : isFeature + ? geojson.geometry + : geojson; + isGeometryCollection = geometryMaybeCollection + ? geometryMaybeCollection.type === "GeometryCollection" + : false; + stopG = isGeometryCollection + ? geometryMaybeCollection.geometries.length + : 1; + + for (var geomIndex = 0; geomIndex < stopG; geomIndex++) { + var multiFeatureIndex = 0; + var geometryIndex = 0; + geometry = isGeometryCollection + ? geometryMaybeCollection.geometries[geomIndex] + : geometryMaybeCollection; + + // Handles null Geometry -- Skips this geometry + if (geometry === null) continue; + coords = geometry.coordinates; + var geomType = geometry.type; + + wrapShrink = + excludeWrapCoord && + (geomType === "Polygon" || geomType === "MultiPolygon") + ? 1 + : 0; + + switch (geomType) { + case null: + break; + case "Point": + if ( + callback( + coords, + coordIndex, + featureIndex, + multiFeatureIndex, + geometryIndex + ) === false + ) + return false; + coordIndex++; + multiFeatureIndex++; + break; + case "LineString": + case "MultiPoint": + for (j = 0; j < coords.length; j++) { + if ( + callback( + coords[j], + coordIndex, + featureIndex, + multiFeatureIndex, + geometryIndex + ) === false + ) + return false; + coordIndex++; + if (geomType === "MultiPoint") multiFeatureIndex++; + } + if (geomType === "LineString") multiFeatureIndex++; + break; + case "Polygon": + case "MultiLineString": + for (j = 0; j < coords.length; j++) { + for (k = 0; k < coords[j].length - wrapShrink; k++) { + if ( + callback( + coords[j][k], + coordIndex, + featureIndex, + multiFeatureIndex, + geometryIndex + ) === false + ) + return false; + coordIndex++; + } + if (geomType === "MultiLineString") multiFeatureIndex++; + if (geomType === "Polygon") geometryIndex++; + } + if (geomType === "Polygon") multiFeatureIndex++; + break; + case "MultiPolygon": + for (j = 0; j < coords.length; j++) { + geometryIndex = 0; + for (k = 0; k < coords[j].length; k++) { + for (l = 0; l < coords[j][k].length - wrapShrink; l++) { + if ( + callback( + coords[j][k][l], + coordIndex, + featureIndex, + multiFeatureIndex, + geometryIndex + ) === false + ) + return false; + coordIndex++; + } + geometryIndex++; + } + multiFeatureIndex++; + } + break; + case "GeometryCollection": + for (j = 0; j < geometry.geometries.length; j++) + if ( + coordEach(geometry.geometries[j], callback, excludeWrapCoord) === + false + ) + return false; + break; + default: + throw new Error("Unknown Geometry Type"); + } + } + } } + }; // γεωμετρία }; //