مكتبة الأشكال الهندسية

  1. نظرة عامة
  2. مفاهيم الهندسة الكروية
    1. دوالّ المسافة والمساحة
    2. وظائف التنقّل
  3. ترميز الأشكال الهندسية
  4. دالتا المضلّع والخطوط المتعدّدة
    1. containsLocation()
    2. isLocationOnEdge()

نظرة عامة

تشير المفاهيم الواردة في هذا المستند إلى الميزات التي تتوفّر فقط في مكتبة google.maps.geometry. لا يتم تحميل مكتبة هذه تلقائيًا عند تحميل واجهة برمجة التطبيقات JavaScript لـ "خرائط Google"، ولكن يجب تحديدها صراحةً من خلال استخدام مَعلمة libraries bootstrap. لمزيد من المعلومات، يُرجى الاطّلاع على نظرة عامة على المكتبات.

توفّر مكتبة الهندسة في واجهة برمجة التطبيقات JavaScript لخرائط Google دوال مفيدة لاحتساب البيانات الهندسية على سطح الأرض. تتضمّن المكتبة ثلاث مساحات أسماء:

  • spherical يحتوي على أدوات هندسة كروية تتيح لك احتساب الزوايا والمسافات والمناطق من خطوط الطول والعرض.
  • encoding يحتوي على أدوات تشفير وفك تشفير مسارات الخطوط المتعددة وفقًا لـ خوارزمية الخطوط المتعددة المشفَّرة.
  • poly تحتوي على دوالّ مساعدة للعمليات الحسابية التي تتضمّن المضلّعات والخطوط المتعددة.

لا تحتوي مكتبة google.maps.geometry على أي فئات، بل تحتوي بدلاً من ذلك على طُرق ثابتة في مساحات имен المذكورة أعلاه.

مفاهيم الهندسة الكروية

الصور ضمن واجهة برمجة التطبيقات JavaScript لـ "خرائط Google" ثنائية الأبعاد و"مسطّحة". ومع ذلك، فإنّ الأرض ثلاثية الأبعاد، وغالبًا ما يتم تقريبها على أنّها إما إسطوانة بيضاوية الشكل أو كرة. في Maps API، نستخدم شكلًا كرويًا، ولتمثّل الكرة الأرضية على سطح مستوٍ ثنائي الأبعاد، مثل شاشة الكمبيوتر، تستخدم Maps API طريقة إسقاط.

في الإسقاطات ثنائية الأبعاد، يمكن أن تكون المظاهر مخادعة في بعض الأحيان. وبما أنّ إسقاط الخريطة يتطلّب بالضرورة بعض التشويه، غالبًا ما لا يكون ينطبق نظرية ermatism Euclidian الهندسية البسيطة. على سبيل المثال، أقصر مسافة بين نقطتَين على كرة ليست خطًا مستقيمًا، بل دائرة كبيرة (نوع من الخطوط الجيوديسية)، وتزيد الزوايا التي تشكّل مثلثًا على سطح الكرة عن 180 درجة.

بسبب هذه الاختلافات، تتطلّب الدوالّ الهندسية على كرة (أو على إسقاطها) استخدام الهندسة الكروية لحساب بنى مثل المسافة والاتجاه والمساحة. تتضمّن مساحة الاسم google.maps.geometry.spherical في واجهة برمجة التطبيقات لتطبيق "خرائط Google" أدوات لحساب هذه الأشكال الهندسية الكروية. يوفّر نطاق الأسماء هذا methods ثابتة لاحتساب القيم القياسية من الإحداثيات الكروية (خطوط الطول والعرض).

دوال المسافة والمساحة

المسافة بين نقطتَين هي طول أقصر مسار بينهما. ويُطلق على هذا المسار الأقصر اسم مسار الجيوديسية. على سطح كرة، تكون جميع المسارات الجيوديسية أجزاءً من دائرة كبيرة. لاحتساب هذه المسافة، يمكنك استدعاء computeDistanceBetween()، مع تمرير عنصرَي LatLng.

يمكنك بدلاً من ذلك استخدام computeLength() لحساب طول مسار معيّن إذا كان لديك عدة مواقع جغرافية.

يتم التعبير عن نتائج المسافة بالأمتار.

لاحتساب مساحة منطقة مضلّعة (بالمتر المربّع)، يمكنك استدعاء computeArea()، مع تمرير مصفوفة من عناصر LatLng التي تحدّد حلقة مغلقة.

عند التنقّل على سطح كروي، يكون العنوان هو زاوية اتجاه من نقطة مرجعية ثابتة، وعادةً ما يكون الاتجاه الشمالي الحقيقي. في Google Maps API، يتم تحديد الاتجاه بالدرجات من الشمال الحقيقي، حيث يتم قياس الاتجاهات بالتناوب مع عقارب الساعة من الشمال الحقيقي (0 درجة). يمكنك احتساب هذا الاتجاه بين موقعَين جغرافيَّين باستخدام الطريقة computeHeading()، مع تمريرها بعنصرَين from وto LatLng.

استنادًا إلى اتجاه معيّن وموقع جغرافي أصلي والمسافة التي يجب قطعها (بالمتر)، يمكنك احتساب إحداثيات الوجهة باستخدام computeOffset().

عند توفُّر عنصرَي LatLng وقيمة تتراوح بين 0 و1، يمكنك أيضًا احتساب وجهة بينهما باستخدام الأسلوب interpolate() الذي يُجري interpolation (إحصاءات تقريبية) خطيًا كروبياً بين الموقعَين الجغرافيَّين، حيث تشير القيمة إلى المسافة الكسورية التي يجب قطعها على طول المسار من المصدر إلى الوجهة.

ينشئ المثال التالي خطَّين متعددَين عند النقر على نقطتَين على الخريطة، وهما خطّ جيوديزيكي وخطّ "مستقيم" يربطان بين الموقعَين الجغرافيَّين، ويحسب اتجاه التنقّل بين النقطتَين:

TypeScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">

let marker1: google.maps.Marker, marker2: google.maps.Marker;
let poly: google.maps.Polyline, geodesicPoly: google.maps.Polyline;

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: 34, lng: -40.605 },
    }
  );

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(
    document.getElementById("info") as HTMLElement
  );

  marker1 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 40.714, lng: -74.006 },
  });

  marker2 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 48.857, lng: 2.352 },
  });

  const bounds = new google.maps.LatLngBounds(
    marker1.getPosition() as google.maps.LatLng,
    marker2.getPosition() as google.maps.LatLng
  );

  map.fitBounds(bounds);

  google.maps.event.addListener(marker1, "position_changed", update);
  google.maps.event.addListener(marker2, "position_changed", update);

  poly = new google.maps.Polyline({
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    map: map,
  });

  geodesicPoly = new google.maps.Polyline({
    strokeColor: "#CC0099",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    geodesic: true,
    map: map,
  });

  update();
}

function update() {
  const path = [
    marker1.getPosition() as google.maps.LatLng,
    marker2.getPosition() as google.maps.LatLng,
  ];

  poly.setPath(path);
  geodesicPoly.setPath(path);

  const heading = google.maps.geometry.spherical.computeHeading(
    path[0],
    path[1]
  );

  (document.getElementById("heading") as HTMLInputElement).value =
    String(heading);
  (document.getElementById("origin") as HTMLInputElement).value = String(
    path[0]
  );
  (document.getElementById("destination") as HTMLInputElement).value = String(
    path[1]
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">
let marker1, marker2;
let poly, geodesicPoly;

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: 34, lng: -40.605 },
  });

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(
    document.getElementById("info"),
  );
  marker1 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 40.714, lng: -74.006 },
  });
  marker2 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 48.857, lng: 2.352 },
  });

  const bounds = new google.maps.LatLngBounds(
    marker1.getPosition(),
    marker2.getPosition(),
  );

  map.fitBounds(bounds);
  google.maps.event.addListener(marker1, "position_changed", update);
  google.maps.event.addListener(marker2, "position_changed", update);
  poly = new google.maps.Polyline({
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    map: map,
  });
  geodesicPoly = new google.maps.Polyline({
    strokeColor: "#CC0099",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    geodesic: true,
    map: map,
  });
  update();
}

function update() {
  const path = [marker1.getPosition(), marker2.getPosition()];

  poly.setPath(path);
  geodesicPoly.setPath(path);

  const heading = google.maps.geometry.spherical.computeHeading(
    path[0],
    path[1],
  );

  document.getElementById("heading").value = String(heading);
  document.getElementById("origin").value = String(path[0]);
  document.getElementById("destination").value = String(path[1]);
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

طرق الترميز

غالبًا ما يتم تحديد المسارات ضمن Maps JavaScript API على أنّها Array من عناصر LatLng. ومع ذلك، غالبًا ما يكون تمرير مثل هذه الصفيفات ضخمًا. يمكنك بدلاً من ذلك استخدام خوارزمية ترميز الخطوط المتعددة من Google لضغط مسار معيّن، والذي يمكنك فيما بعد إزالة ضغطه من خلال فك التشفير.

تحتوي مكتبة geometry على مساحة اسم encoding للأدوات اللازمة لتشفير الخطوط المتعددة وفك تشفيرها.

تُشفِّر الطريقة الثابتة encodePath() المسار المحدَّد. يمكنك تمرير صفيف من LatLng أو MVCArray (الذي يتم إرجاعه من Polyline.getPath()).

لفك ترميز مسار مشفّر، استخدِم decodePath() مع تمرير السلسلة المشفّرة إلى الطريقة.

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

TypeScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 14,
      center: { lat: 34.366, lng: -89.519 },
    }
  );
  const poly = new google.maps.Polyline({
    strokeColor: "#000000",
    strokeOpacity: 1,
    strokeWeight: 3,
    map: map,
  });

  // Add a listener for the click event
  google.maps.event.addListener(map, "click", (event) => {
    addLatLngToPoly(event.latLng, poly);
  });
}

/**
 * Handles click events on a map, and adds a new point to the Polyline.
 * Updates the encoding text area with the path's encoded values.
 */
function addLatLngToPoly(
  latLng: google.maps.LatLng,
  poly: google.maps.Polyline
) {
  const path = poly.getPath();

  // Because path is an MVCArray, we can simply append a new coordinate
  // and it will automatically appear
  path.push(latLng);

  // Update the text field to display the polyline encodings
  const encodeString = google.maps.geometry.encoding.encodePath(path);

  if (encodeString) {
    (document.getElementById("encoded-polyline") as HTMLInputElement).value =
      encodeString;
  }
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 14,
    center: { lat: 34.366, lng: -89.519 },
  });
  const poly = new google.maps.Polyline({
    strokeColor: "#000000",
    strokeOpacity: 1,
    strokeWeight: 3,
    map: map,
  });

  // Add a listener for the click event
  google.maps.event.addListener(map, "click", (event) => {
    addLatLngToPoly(event.latLng, poly);
  });
}

/**
 * Handles click events on a map, and adds a new point to the Polyline.
 * Updates the encoding text area with the path's encoded values.
 */
function addLatLngToPoly(latLng, poly) {
  const path = poly.getPath();

  // Because path is an MVCArray, we can simply append a new coordinate
  // and it will automatically appear
  path.push(latLng);

  // Update the text field to display the polyline encodings
  const encodeString = google.maps.geometry.encoding.encodePath(path);

  if (encodeString) {
    document.getElementById("encoded-polyline").value = encodeString;
  }
}

window.initMap = initMap;
عرض مثال

تجربة عيّنة

دوال المضلّعات والمخطّطات المتعدّدة الخطوط

تحتوي مساحة الاسم poly لمكتبة الهندسة على دوال مساعدة تحدِّد ما إذا كانت نقطة معيّنة داخل مضلّع أو خط متعدّد الأضلاع أو بالقرب منه.

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

لمعرفة ما إذا كانت نقطة معيّنة تقع ضمن مضلّع، مرِّر النقطة والمضلّع إلى google.maps.geometry.poly.containsLocation(). تعرِض دالات القيمة true إذا كانت النقطة داخل المضلّع أو على حوافه.

يُسجِّل الرمز البرمجي التالي القيمة "صحيح" في وحدة تحكّم المتصفّح إذا كان نقر المستخدم يقع ضمن المثلث المحدّد، وإلا يُسجِّل القيمة "خطأ".

function initialize() {
  var mapOptions = {
    zoom: 5,
    center: new google.maps.LatLng(24.886, -70.269),
    mapTypeId: 'terrain'
  };

  var map = new google.maps.Map(document.getElementById('map'),
      mapOptions);

  var bermudaTriangle = new google.maps.Polygon({
    paths: [
      new google.maps.LatLng(25.774, -80.190),
      new google.maps.LatLng(18.466, -66.118),
      new google.maps.LatLng(32.321, -64.757)
    ]
  });

  google.maps.event.addListener(map, 'click', function(event) {
    console.log(google.maps.geometry.poly.containsLocation(event.latLng, bermudaTriangle));
  });
}

google.maps.event.addDomListener(window, 'load', initialize);

يرسم إصدار آخر من هذا الرمز مثلثًا أزرقًا على الخريطة إذا كانت النقرة تقع داخل مثلث برمودا، ودائرة حمراء في غير ذلك:

عرض مثال

isLocationOnEdge()

isLocationOnEdge(point:LatLng, poly:Polygon|Polyline, tolerance?:number)

لتحديد ما إذا كانت النقطة تقع على خطّ متعدّد الأضلاع أو بالقرب منه، أو على حافة مضلّع أو بالقرب منها، نقْل النقطة وخطّ الخطوط المتعددة/المضلّع وقيمة اتّساع النطاق اختياريًا بالدرجات إلى google.maps.geometry.poly.isLocationOnEdge(). تعرِض الدالة القيمة true إذا كانت المسافة بين النقطة وأقرب نقطة على خط أو الحافة تقع ضمن حدود التسامح المحدّدة. القيمة التلقائية للسماح هي 10-9 درجة.

function initialize() {
  var myPosition = new google.maps.LatLng(46.0, -125.9);

  var mapOptions = {
    zoom: 5,
    center: myPosition,
    mapTypeId: 'terrain'
  };

  var map = new google.maps.Map(document.getElementById('map'),
      mapOptions);

  var cascadiaFault = new google.maps.Polyline({
    path: [
      new google.maps.LatLng(49.95, -128.1),
      new google.maps.LatLng(46.26, -126.3),
      new google.maps.LatLng(40.3, -125.4)
    ]
  });

  cascadiaFault.setMap(map);

  if (google.maps.geometry.poly.isLocationOnEdge(myPosition, cascadiaFault, 10e-1)) {
    alert("Relocate!");
  }
}

google.maps.event.addDomListener(window, 'load', initialize);