javascript موقعي - تحقق من ما إذا كانت النقطة هي الأرض أو المياه في خرائط Google




جوجل شرح (15)

تمكنت من الاقتراب عن طريق استخدام Google Elevation API. وهنا صورة للنتائج:

ترى السداسيات تشبه إلى حد كبير الأرض ، على الرغم من تحديد محيط مستطيل يذهب جزئيًا إلى الماء. في هذه الحالة ، أجريت فحصًا سريعًا من خرائط Google نفسها وكان الحد الأدنى للارتفاع على الأرض حوالي 8-9 متر ، لذا كان الحد الأدنى. يتم نسخ / نسخ الشفرة في الغالب من وثائق Google و Stack Overflow ، في ما يلي النص الكامل:

https://gist.github.com/dvas0004/fd541a0502528ebfb825

.. ثم خرائط جوجل "تقسيم المياه من المياه"

حسنا ، ليس بالمعنى التوراتي ولكن ..

أود أن أعرف ما هي الخيارات المتاحة أمامي للتحقق من أن نقطة [خط الطول ، خط الطول] هي الأرض أو المياه.

من الواضح أن خرائط Google تحتوي على هذه البيانات (هيئات المياه زرقاء) - ولكن هل هناك شيء في واجهة برمجة التطبيقات يمكنني استخدامه لذلك؟ وإن لم يكن - هل هم لا يخدمون ذلك لأنهم لم يفكروا به أبداً؟ أو لأنها معقدة للغاية؟

لم أجد أي معلومات حول هذه المسألة - باستثناء بعض الأسئلة المشابهة هنا (مثل العثور على نوع من التضاريس ، أو الارتفاع - ولكن ليس بالضبط ما أحتاج).

هل توجد طبقة منفصلة لذلك؟ خيار؟ أمر؟ أو يجب أن أذهب للقيام بذلك يدويا؟

الطريقة الوحيدة التي يمكنني التفكير بها في كيفية التعامل مع هذا (إذا كنت بحاجة إلى القيام بذلك يدويًا) هي التحقق من كل نقطة عرض للاستعلام عن النقطة المحددة - ثم تحقق من قيمة RGB لصورة خريطة Google تلك. هذا فقط على النظرية - لأنه في الممارسة العملية - ليس لدي أي فكرة عن كيفية تحقيق ذلك ، فإن العقبة الأولى هي أنني لا أعرف كيف يمكنني تحويل موقع بكسل على مربع إلى نقطة [LatLon] على سبيل المثال

سيكون الحل الجاهز أسهل بكثير.

لاحظ أني لا أحتاج إلى كل الماء في العالم (على سبيل المثال - لا يهمني تيارات المياه أو البرك الصغيرة أو معظم الأنهار أو حمام السباحة الخاص بالجيران. أحتاج إلى النقاط التي يمكن للشخص أن يغامر بها دون مساعدة مركبة عائمة )

تحرير أنا

بعد قراءة التعليقات: طريقة الارتفاع غير موثوق بها ، هناك الكثير من الأماكن أدناه مستوى البحر (يمكنك رؤية قائمة "الأعمق" 10 هنا http://geology.com/below-sea-level/ ) وهناك الكثير من المسطحات المائية غير المغلقة فوق مستوى سطح البحر (البحيرات). لا يمكن الاعتماد على طريقة تحديد الموقع الجغرافي العكسية لأنها ستعيد كيانًا جغرافيًا ، مثل المدينة أو الولاية - أو مرات عديدة. لقد نظرت بالفعل في تلك الحلول الزائفة قبل طرح السؤال - لكن أيا منهم لم يجيب على السؤال - هذه الأساليب سيئة "التخمين" في أحسن الأحوال.


هناك واجهة ويب مجانية API التي تحل بالضبط هذه المشكلة تسمى onwater.io . إنه ليس شيئًا مدمجًا في خرائط Google ، ولكن نظرًا لخط العرض وخط العرض ، فسيتم إرجاعه صوابًا أو خطأ عن طريق طلب الحصول عليه.

مثال على الماء: https://api.onwater.io/23.92323,-66.3

{
  lat: 23.92323,
  lon: -66.3,
  water: true
}

مثال على الأرض: https://api.onwater.io/42.35,-71.1

{
  lat: 42.35,
  lon: -71.1,
  water: false
}

الكشف الكامل أعمل في Dockwa.com ، الشركة وراء onwater. بنينا على الماء لحل هذه المشكلة بأنفسنا ومساعدة المجتمع. إنه مجاني دائمًا للاستخدام و أردنا مشاركته :)


لدي حل مختلف هنا. في تطبيق خريطة جوجل الحالية ، فإنه لا يحسب الاتجاه / المسافة من موقع الماء إلى موقع الأرض والعكس بالعكس. لماذا لا نستخدم هذا المنطق لتحديد ما إذا كانت النقطة هي الأرض أو الماء.

على سبيل المثال ، لنأخذ هذا المثال

إذا أردنا أن نحدد ، إذا كانت النقطة x هي الأرض أو الماء ، إذن

دعونا نتحقق من الاتجاه بين النقطة x ونقطة معروفة y وهي الأرض. إذا كان يحدد الاتجاه / المسافة فإن النقطة x هي الأرض وإلا فهي المياه.


هذا ما أستخدمه وهو يعمل ليس سيئا للغاية ... يمكنك تحسين الاختبار إذا كان لديك المزيد من وحدات المعالجة المركزية لتضيع عن طريق إضافة بكسل.

function isItWatter($lat,$lng) {

    $GMAPStaticUrl = "https://maps.googleapis.com/maps/api/staticmap?center=".$lat.",".$lng."&size=40x40&maptype=roadmap&sensor=false&zoom=12&key=YOURAPIKEY";  
    //echo $GMAPStaticUrl;
    $chuid = curl_init();
    curl_setopt($chuid, CURLOPT_URL, $GMAPStaticUrl);   
    curl_setopt($chuid, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($chuid, CURLOPT_SSL_VERIFYPEER, FALSE);
    $data = trim(curl_exec($chuid));
    curl_close($chuid);
    $image = imagecreatefromstring($data);

    // this is for debug to print the image
    ob_start();
    imagepng($image);
    $contents =  ob_get_contents();
    ob_end_clean();
    echo "<img src='data:image/png;base64,".base64_encode($contents)."' />";

    // here is the test : I only test 3 pixels ( enough to avoid rivers ... )
    $hexaColor = imagecolorat($image,0,0);
    $color_tran = imagecolorsforindex($image, $hexaColor);

    $hexaColor2 = imagecolorat($image,0,1);
    $color_tran2 = imagecolorsforindex($image, $hexaColor2);

    $hexaColor3 = imagecolorat($image,0,2);
    $color_tran3 = imagecolorsforindex($image, $hexaColor3);

    $red = $color_tran['red'] + $color_tran2['red'] + $color_tran3['red'];
    $green = $color_tran['green'] + $color_tran2['green'] + $color_tran3['green'];
    $blue = $color_tran['blue'] + $color_tran2['blue'] + $color_tran3['blue'];

    imagedestroy($image);
    var_dump($red,$green,$blue);
    //int(492) int(570) int(660) 
    if($red == 492 && $green == 570 && $blue == 660)
        return 1;
    else
        return 0;
}

إليك مثال آخر في جافا سكريبت خالص: http://jsfiddle.net/eUwMf/

كما ترى ، فإن أداة "ideia" هي في الأساس حالة rebe100x ، والحصول على الصورة من واجهة برمجة تطبيقات الخرائط الثابتة من Google ، وقراءة البكسل الأول:

$("#xGps, #yGps").change(function() {
    var img = document.getElementById('mapImg');

    // Bypass the security issue : drawing a canvas from an external URL.
    img.crossOrigin='anonymous';

    var xGps = $("#xGps").val();
    var yGps = $("#yGps").val();

    var mapUrl = "http://maps.googleapis.com/maps/api/staticmap?center=" + xGps + "," + yGps +
        "&zoom=14&size=20x20&maptype=roadmap&sensor=false";

    // mapUrl += "&key=" + key;

    $(img).attr("src", mapUrl);

    var canvas = $('<canvas/>')[0];
    canvas.width = img.width;
    canvas.height = img.height;
    canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);

    var pixelData = canvas.getContext('2d').getImageData(1, 1, 1, 1).data;

    if (pixelData[0] == 164 &&
        pixelData[1] == 190 &&
        pixelData[2] == 220) {
        $("#result").html("Water");
    } else {
        $("#result").html("Not water");
    }
});

هذه الطريقة غير موثوق بها تماما. في الواقع ، فإن البيانات التي تم إرجاعها تعتمد بشكل كامل على أي جزء من العالم الذي تعمل معه. على سبيل المثال ، أعمل في فرنسا. إذا نقرت على البحر على ساحل فرنسا ، فستعرض Google أقرب موقع LAND يمكنه "تخمينه" على. عندما طلبت معلومات من Google عن هذا السؤال نفسه ، أجابوا أنهم غير قادرين على إرجاع النقطة المطلوبة بدقة في كتلة مائية.

لا إجابة مرضية للغاية ، وأنا أعلم. هذا محبط للغاية ، خاصة بالنسبة لنا نحن الذين يوفرون للمستخدم القدرة على النقر على الخريطة لتحديد موقف علامة.


لا يبدو ممكنًا مع أي خدمة Google الحالية.

ولكن هناك خدمات أخرى ، مثل خدمة Coordinates Vector JSON Query ! يمكنك ببساطة الاستعلام عن البيانات في عنوان URL ، واستعادة استجابة JSON / XML .

مثال على الطلب: http://api.koordinates.com/api/vectorQuery.json?key=YOUR_GEODATA_KEY&layer=1298&x=-159.9609375&y=13.239945499286312&max_results=3&radius=10000&geometry=true&with_field_names=true

يجب عليك التسجيل وتزويد المفتاح ورقم الطبقة المختار. يمكنك البحث في جميع مستودعاتها من الطبقات المتاحة . معظم الطبقات إقليمية فقط ، ولكن يمكنك العثور على العالمية أيضًا ، مثل الخط الساحلي العالمي :

عند تحديد طبقة ، انقر فوق علامة التبويب "الخدمات" ، وستحصل على عنوان URL لطلب المثال. أعتقد أنك تحتاج فقط للتسجيل وهذا كل شيء!

والآن الأفضل:

يمكنك تحميل طبقة الخاص بك!

لا يتوفر على الفور ، مهلا يجب معالجته بطريقة ما ، ولكن يجب أن يعمل! يبدو مستودع الطبقات بالفعل وكأنه أشخاص تم تحميلهم حسب الحاجة.


هنا هو حل بسيط

نظرًا لأن Google لا تقدم نتائج موثوقة فيما يتعلق بالإحداثيات التي تقع على أي من المحيطات أو في مسطحات المياه الداخلية ، تحتاج إلى استخدام خدمة نسخ احتياطي أخرى ، مثل ياندكس ، للمساعدة في توفير هذه المعلومات المهمة عند فقدها. على الأرجح لن ترغب في استخدام ياندكس كمعلمك الجغرافي الأساسي نظرًا لأن Google تفوق بكثير في موثوقية واكتمال بيانات العالم ، ومع ذلك يمكن أن تكون ياندكس مفيدة جدًا لغرض استرجاع البيانات عندما يتعلق الأمر بالإحداثيات على أجسام المياه ، لذلك استخدم كليهما.

وثائق ياندكس: https://api.yandex.com.tr/maps/doc/geocoder/desc/concepts/input_params.xml

الخطوات لاسترداد اسم المحيط:

1.) استخدم Google أولاً لعكس الرمز الجغرافي للإحداثيات.

2.) إذا أرجعت Google نتائج الصفر ، فمن المحتمل أن يكون التنسيق بنسبة 99٪ على محيط. الآن قم بعمل طلب ترميز جغرافي عكسي ثانٍ بنفس الإحداثيات إلى ياندكس. سوف يعيد ياندكس استجابة JSON مع الإحداثيات الدقيقة ، ضمن هذه الاستجابة سيكون "مفتاحين": أزواج "القيمة" من الأهمية

["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]

and

["GeoObject"]["name"]

تحقق من المفتاح اللطيف ، إذا كانت = "hydro" تعرف أنك فوق جسم من الماء ، ولأن Google عادت بنتائج صفرية فمن المحتمل 99.99٪ أن تكون هذه المياه من المحيط. سيكون اسم المحيط هو مفتاح "الاسم" أعلاه.

هنا مثال على كيفية استخدام هذه الاستراتيجية المكتوبة في روبي

if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
     ocean = result.data["GeoObject"]["name"] 
end

الخطوات لاسترداد اسم جسم المياه الداخلية:

على سبيل المثال ، نفترض أن تنسيقنا يكمن في بحيرة في مكان ما:

1.) استخدم Google أولاً لعكس الرمز الجغرافي للإحداثيات.

2.) ستقوم Google على الأرجح بإرجاع نتيجة تمثل عنوانًا افتراضيًا بارزًا على الأرض المجاورة. في هذه النتيجة ، فإنها توفر إحداثيات العنوان الذي تم إرجاعه ، ولن يتوافق هذا التنسيق مع التنسيق الذي قدمته. قس المسافة بين الإحداثيات التي أدخلتها والجهة التي تم إرجاعها مع النتيجة ، إذا كانت مختلفة بشكل كبير (على سبيل المثال 100 ياردة) ، ثم قم بإجراء طلب نسخ احتياطي ثانوي باستخدام Yandex وتحقق من قيمة المفتاح "kind" ، إذا كان هو "hydro" ثم تعرف أن الإحداثيات تقع على الماء. نظرًا لأن Google أعادت النتيجة على عكس المثال أعلاه ، فمن المرجح 99.99٪ أنه جسم مائي داخلي لذلك يمكنك الآن الحصول على الاسم. إذا لم يكن "kind" == "hydro" ، فاستخدم كائن Google المشفر جغرافيًا.

["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"]

and

["GeoObject"]["name"]

هنا هو نفس رمز مكتوب في روبي للحصول على inland_body_of_water

if result.data["GeoObject"]["metaDataProperty"]["GeocoderMetaData"]["kind"] == "hydro"
     inland_body_of_water = result.data["GeoObject"]["name"] 
end

ملاحظة حول الترخيص: حسب علمي ، لا تسمح لك Google باستخدام بياناتها للعرض على أي خرائط أخرى بخلاف تلك التي تقدمها Google. لكن ياندكس لديها ترخيص مرن للغاية ، ويمكنك استخدام بياناتها ليتم عرضها على خرائط جوجل.

كما أن ياندكس لديها حد مرتفع لمعدل الطلبات يبلغ 50000 طلب / يوم مجانًا ، وبدون مفتاح واجهة برمجة التطبيقات المطلوب.


هذه طريقتين مختلفتين ، يمكنك أن تجرب:

  • يمكنك استخدام Geocoding عكس خرائط جوجل . في مجموعة النتائج يمكنك تحديد ما إذا كان الماء عن طريق التحقق من types . في حالة المياه ، يكون النوع natural_feature . انظر المزيد على هذا الرابط http://code.google.com/apis/maps/documentation/geocoding/#Types .

    كما تحتاج إلى التحقق من أسماء الميزات ، إذا كانت تحتوي على Sea, Lake, Ocean وبعض الكلمات الأخرى ذات الصلة بالمياه لمزيد من الدقة. على سبيل المثال الصحارى هي أيضا natural_feature s.

    Prons - سيتم تنفيذ جميع عمليات الاكتشاف على جهاز العميل. لا تحتاج إلى إنشاء خدمة جانب الخادم الخاصة.

    سلبيات - غير دقيق للغاية وفرص الحصول على "لا شيء" في المياه عالية جدا.

  • يمكنك اكتشاف المياه / الأراضي حسب البكسل ، وذلك باستخدام Google Static Maps . لكن لهذا الغرض تحتاج إلى إنشاء خدمة http.

    هذه خطوات يجب أن تقوم بها خدمتك:

    1. تلقي latitude longitude current zoom من العميل.
    2. أرسل http://maps.googleapis.com/maps/api/staticmap?center={ latitude , longitude }&zoom={ current zoom`} & size = 1x1 & maptype = roadmap & sensor = request false to Google Static Map service.
    3. كشف لون البيكسل للصورة الثابتة 1 × 1.
    4. الرد على معلومات حول الكشف.

    لا يمكنك اكتشاف لون البيكسل في جانب العميل. نعم ، يمكنك تحميل صورة ثابتة على جهاز العميل ورسم صورة على عنصر canvas . ولكن لا يمكنك استخدام getImageData من سياق اللوحة للحصول على لون البيكسل. هذا مقيّد بسياسة نطاق مشترك.

    Prons - كشف دقيق للغاية

    سلبيات - استخدام موارد الخادم الخاصة للكشف


بالإضافة إلى الترميز الجغرافي العكسي - كما أشار Dr.Molle موللي ، قد يعود إلى ZERO_RESULTS - يمكنك استخدام خدمة Elevation. إذا لم تحصل على نتائج صفرية عن طريق الترميز الجغرافي العكسي ، فاحصل على ارتفاع الموقع. عموما البحر يحصل على رقم سلبي لأن قاع البحر تحت مستوى سطح البحر. هناك مثال كامل لعمل خدمة الارتفاعات على http://www.daftlogic.com/sandbox-google-maps-find-altitude.htm .

ضع في اعتبارك أنه نظرًا لعدم إتاحة Google لهذه المعلومات ، فإن أي طريقة أخرى هي مجرد تخمين ، وأن التخمينات غير دقيقة بطبيعتها. ومع ذلك ، فإن استخدام type إرجاعه عن طريق التشفير الجغرافي العكسي ، أو الارتفاع في حالة عدم توفر type ، سيغطي معظم الاحتمالات.



للأسف ، هذه الإجابة ليست ضمن واجهة برمجة تطبيقات خرائط Google والمورد المشار إليه ليس مجانيًا ، ولكن هناك خدمة ويب مقدمة من DynamicGeometry تعرض عملية GetWaterOrLand التي تقبل زوجًا من خطوط الطول والعرض ( يمكنك مشاهدة عرض توضيحي هنا ).

أفهم كيف يتم تنفيذ ذلك عن طريق استخدام ملفات شكل الجسم المائي. كيف يتم استخدام ملفات الأشكال هذه بالضبط مع API لخرائط Google ، ولكن قد تتمكن من الحصول على بعض المعلومات من العرض التوضيحي المرتبط.

على أمل أن يساعد بطريقة أو بأخرى.


اعتقدت أنه من الأكثر إثارة للاهتمام القيام بهذا الاستعلام محليًا ، لذا يمكنني أن أكون أكثر اعتمادًا على الذات: دعنا نقول إنني أريد إنشاء 25000 إحداثيات أرض عشوائية دفعة واحدة ، فأنا أفضل الرغبة في تجنب المكالمات إلى واجهات برمجة تطبيقات خارجية قد تكون مكلفة. هنا هو طلقة بلدي في هذا الثعبان ، وذلك باستخدام مثال الثعبان ذكر من قبل TomSchober. فهي في الأساس تبحث عن إحداثيات على ملف 350MB معد مسبقاً يحتوي على جميع إحداثيات الأرض ، وإذا كانت الإحداثيات موجودة هناك ، فإنها تطبعها.

import ogr
from IPython import embed
import sys

drv = ogr.GetDriverByName('ESRI Shapefile') #We will load a shape file
ds_in = drv.Open("land_polygons.shp")    #Get the contents of the shape file
lyr_in = ds_in.GetLayer(0)    #Get the shape file's first layer

#Put the title of the field you are interested in here
idx_reg = lyr_in.GetLayerDefn().GetFieldIndex("P_Loc_Nm")

#If the latitude/longitude we're going to use is not in the projection
#of the shapefile, then we will get erroneous results.
#The following assumes that the latitude longitude is in WGS84
#This is identified by the number "4236", as in "EPSG:4326"
#We will create a transformation between this and the shapefile's
#project, whatever it may be
geo_ref = lyr_in.GetSpatialRef()
point_ref=ogr.osr.SpatialReference()
point_ref.ImportFromEPSG(4326)
ctran=ogr.osr.CoordinateTransformation(point_ref,geo_ref)

def check(lon, lat):
    #Transform incoming longitude/latitude to the shapefile's projection
    [lon,lat,z]=ctran.TransformPoint(lon,lat)

    #Create a point
    pt = ogr.Geometry(ogr.wkbPoint)
    pt.SetPoint_2D(0, lon, lat)

    #Set up a spatial filter such that the only features we see when we
    #loop through "lyr_in" are those which overlap the point defined above
    lyr_in.SetSpatialFilter(pt)

    #Loop through the overlapped features and display the field of interest
    for feat_in in lyr_in:
        # success!
        print lon, lat

check(-95,47)

حاولت الإحداثيات اثنتي عشرة ، أنها تعمل بشكل رائع. يمكن تنزيل ملف "land_polygons.shp" من هنا ، تكملات OpenStreetMaps. (استخدمت أول رابط تنزيل WGS84 بنفسي ، ربما يعمل الثاني أيضًا)


أوصي المتداول بنفسك هنا. يمكنك استخدام أدوات مثل GDAL للاستعلام عن المحتويات تحت نقطة في ملف shapefile. يمكنك الحصول على ملفات صور عن الجغرافيا الأمريكية من مصادر عديدة ، بما في ذلك مكتب الإحصاء الأمريكي .

يمكن القيام بذلك عبر الثنائيات GDAL أو المصدر C أو عبر swig في Java و Python وغير ذلك.

خرائط التعداد

GDAL

مثال على الاستعلام عن نقطة في بايثون


لقد تم استخدام Jasob لسنوات ، ومن الأيدي أسفل المفترس أفضل هناك.
يحتوي على واجهة مستخدم متطورة ولكن لا يزال بديهيا وسهل الاستخدام.
وستتناول أيضًا ملفات HTML و CSS.

أفضل طريقة لاستخدامها هي بادئة جميع المتغيرات الخاصة بك بشيء مثل تسطير أسفل السطر ، ثم استخدام ميزة sort لتجميعها جميعًا معًا وتحديدها كأهداف للتشويش.

لا يزال بإمكان المستخدمين عرض المصدر الخاص بك ، ولكن من الصعب فك _sUserPreferredNickName عندما يتم تحويل المتغيرات الخاصة بك من شيء مثل _sUserPreferredNickName إلى.

سيقوم المحرك تلقائيا بزيادة عدد المتغيرات المستهدفة وتحديد أولوياتها للحصول على الحد الأقصى للضغط.

أنا لا أعمل مع Jasob ولا أحصل على أي شيء من الترويج لها ، فقط تقديم بعض النصائح الودية.
الجانب السلبي هو أنه ليس مجانيًا وباهظ الثمن ، لكنه لا يزال يستحق العناء عند تكديسه مع البدائل - فالخيارات "المجانية" لا تقترب حتى من ذلك.





javascript google-maps google-maps-api-3