יותר

כיצד ניתן לדעת אם נתיב GeoJSON מצטלב עם תכונה אחרת בעלון?

כיצד ניתן לדעת אם נתיב GeoJSON מצטלב עם תכונה אחרת בעלון?


יש לי יישום שבו המשתמש מצייר נתיב (סדרה של קווים ישרים מחוברים) וייתכן ונתיב זה לא יחתוך שום תכונה בשכבת GeoJSON מסוימת.

אני צריך לבדוק ששום נקודה בקווים אלה לא חוצה את שכבת GeoJSON, ולא רק את נקודות הקצה.

כיצד אוכל לבצע בדיקה זו?


אתה יכול לנסות את ספריית Turf ושיטה כמו צומת: http://turfjs.org/docs/#intersect

הנה דוגמת הקוד מאותה ספרייה:

var poly1 = {"type": "Feature", "geometry": {"type": "מצולע", "קואורדינטות": [[[-122.801742, 45.48565], [-122.801742, 45.60491], [-122.584762, 45.60491 ], [-122.584762, 45.48565], [-122.801742, 45.48565]]}} var poly2 = {"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [[ [-122.520217, 45.535693], [-122.64038, 45.553967], [-122.720031, 45.526554], [-122.669906, 45.507309], [-122.723464, 45.446643], [-122.532577, 45.408574], [-12.4.4.464643] -122.520217, 45.535693]]]}} צומת var = turf.intersect (poly1, poly2);

לַעֲרוֹך: ראה את הכינור של gbs מההערה לעיל לפיתרון פשוט יותר וטוב יותר באמצעות turf.js. התשובה המקורית הבאה:


הנה גרסה שונה של שגרת הצמתים מספריית geojson-js-utils הלוקחת את קווי העברת GeoJSON כקלט ומייצרת נקודות GeoJSON של צומתם כפלט:

function lineStringsIntersect (l1, l2) {var מצטלב = []; עבור (var i = 0; i <= l1.coordinates.length - 2; ++ i) {for (var j = 0; j <= l2.coordinates.length - 2; ++ j) {var a1Latlon = L .latLng (l1.coordinates [i] [1], l1.coordinates [i] [0]), a2Latlon = L.latLng (l1.coordinates [i + 1] [1], l1.coordinates [i + 1] [0]), b1Latlon = L.latLng (l2. קואורדינטות [j] [1], l2. קואורדינטות [j] [0]), b2Latlon = L.latLng (l2. קואורדינטות [j + 1] [1], l2. קואורדינטות [j + 1] [0]), a1 = L.Projection.SphericalMercator.project (a1Latlon), a2 = L.Projection.SphericalMercator.project (a2Latlon), b1 = L.Projection.SphericalMercator.project (b1Latlon) ), b2 = L.Projection.SphericalMercator.project (b2Latlon), ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1. x - b1.x), ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x), u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y); אם (u_b! = 0) {var ua = ua_t / u_b, ub = ub_t / u_b; אם (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {var pt_x = a1.x + ua * (a2.x - a1.x), pt_y = a1.y + ua * (a2.y - a1.y), pt_xy = {"x": pt_x, "y": pt_y}, pt_latlon = L.Projection.SphericalMercator.unproject (pt_xy); intersects.push ({'type': 'Point', 'coordinates': [pt_latlon.lng, pt_latlon.lat]}); }}}} אם (מצטלב.אורך == 0) מצטלב = שקר; החזרת צמתים; }

השינויים היו נחוצים מכיוון שהפונקציה המקורית חישבה צמתים מקו רוחב ואורך בלבד, כאילו היו רק קואורדינטות במישור, והניבו תוצאות לא מדויקות (במיוחד בקווי רוחב גבוהים או למרחקים גדולים). באמצעותL.Projectionלהמיר למערכת קואורדינטות מתוכננת קונפורמית (או, במקרה זה כמעט קונפורמי) במהלך החישוב מתקנת זאת.

אפשר לשנות את זה עוד יותר כדי לקבל אובייקטים גיאומטריים בעלון במקום רק LineStrings, אך במקום זאת השתמשתי בפונקציה די מסורבלת זו כדי ליצור LineStrings שיעברו לפונקציית הצומת:

function lineify (inputGeom) {var outputLines = {"type": "GeometryCollection", "geometries": []} switch (inputGeom.type) {case "GeometryCollection": for (var i in inputGeom.geometries) {var geomLines = lineify (inputGeom.geometries [i]); אם (geomLines) {עבור (var j ב- geomLines.geometries) {outputLines.geometries.push (geomLines.geometries [j]); }} אחר {outputLines = false; } } לשבור; מקרה "Feature": var geomLines = lineify (inputGeom.geometry); אם (geomLines) {עבור (var j ב- geomLines.geometries) {outputLines.geometries.push (geomLines.geometries [j]); }} אחר {outputLines = false; } לשבור; מקרה "FeatureCollection": עבור (var i ב- inputGeom.features) {var geomLines = lineify (inputGeom.features [i] .geometry); אם (geomLines) {עבור (var j ב- geomLines.geometries) {outputLines.geometries.push (geomLines.geometries [j]); }} אחר {outputLines = false; } } לשבור; מקרה "LineString": outputLines.geometries.push (inputGeom); לשבור; מקרה "MultiLineString": מקרה "מצולע": עבור (var i ב- inputGeom.coordinates) {outputLines.geometries.push ({"type": "LineString", "coordinates": inputGeom.coordinates [i]}); } לשבור; מקרה "MultiPolygon": עבור (var i ב- inputGeom.coordinates) {for (var j in inputGeom.coordinates [i]) {outputLines.geometries.push ({"type": "LineString", "coordinates": inputGeom.coordinates [i] [j]}); } } לשבור; ברירת מחדל: outputLines = false; } להחזיר outputLines; }

ופונקציה זו לקחת אובייקטים בעלון, להמיר אותם ל- LineStrings ולבדוק צמתים:

פונקציה crossCheck (baseLayer, drawLayer) {var baseJson = baseLayer.toGeoJSON (), drawJson = drawLayer.toGeoJSON (), baseLines = lineify (baseJson), drawLines = lineify (drawJson), crossPoints = {type: "GeometryCollection", geometries: []}; אם (baseLines && drawLines) {for (var i in drawLines.geometries) {for (var j ב- baseLines.geometries) {var crossTest = lineStringsIntersect (drawLines.geometries [i], baseLines.geometries [j]); אם (crossTest) {עבור (var k ב- crossTest) {crossPoints.geometries.push (crossTest [k]); }}}}} החזר נקודות חוצה; }

הנה דוגמה לכינור המשתמש בזה עם Leaflet.draw:

http://fiddle.jshell.net/nathansnider/egzxw86h/

לאחר שתסיים לצייר אובייקט, הוא יציב סמנים על המפה בנקודות בהן האובייקט המצויר מצטלב עם גיאומטריית הבסיס. הוא לא יכול לבדוק אם יש צמתים בזמן שביל עדיין מצויר, מכיוון ש- Leaflet.draw לא נותן לנו מטפלים באירועים להשתמש בהם בזמן שהציור עדיין בעיצומו. זה ייבדק ברגע שאירוע הגרלה יושלם.

שים לב גם שזה לא יאתר צמתים בשבילים שנמצאים לחלוטין בתוך מצולעים שהם נבדקים כנגד. אתה יכול לעשות את הבדיקות באמצעות turf.js (כנראה בשילוב turf.explode עם turf.within).