Maison  >  Article  >  développement back-end  >  Comment utiliser le langage Go pour développer la fonction de plage de livraison à emporter du système de commande

Comment utiliser le langage Go pour développer la fonction de plage de livraison à emporter du système de commande

WBOY
WBOYoriginal
2023-11-01 10:33:171035parcourir

Comment utiliser le langage Go pour développer la fonction de plage de livraison à emporter du système de commande

Avec le développement du secteur des plats à emporter, la fonction de gamme de livraison à emporter est devenue un point fonctionnel très important dans le système de commande à emporter. Afin de répondre aux besoins des utilisateurs, de nombreuses plateformes de livraison de nourriture proposeront une telle fonction. Alors comment utiliser le langage Go pour développer cette fonction de plage de livraison ? Cet article présentera ce processus en détail et fournira des exemples de code spécifiques afin que les lecteurs puissent mieux comprendre et maîtriser l'implémentation de cette fonction.

  1. Prérequis

Avant de commencer le développement, nous devons d'abord comprendre les exigences et la mise en œuvre de cette fonction. Plus précisément :

  • Vous devez indiquer une zone polygonale, c'est-à-dire la plage de service de livraison à emporter
  • Lorsque l'utilisateur saisit l'adresse sur la page de commande, il doit juger si elle se situe dans la plage de service en fonction de la l'emplacement de l'utilisateur, afin de décider si prendre les commandes.

Afin de mettre en œuvre cette fonction, nous devons utiliser certains outils et technologies :

  • Tout d'abord, nous devons utiliser un service API de carte pour obtenir les données de plage de service dont nous avons besoin et les informations géographiques de l'emplacement de l'utilisateur.
  • Deuxièmement, nous devons utiliser l'algorithme du polygone, c'est-à-dire l'algorithme du point dans le polygone, pour déterminer si le point de positionnement se trouve dans la plage de service.
  • Enfin, nous devons regrouper ces outils dans une bibliothèque de codes à utiliser dans le système de commande.
  1. Idée de conception

Avant d'implémenter cette fonction, nous devons définir quelques structures de données et interfaces de base :

  • Zone de polygone : un tableau qui stocke les informations géographiques de plusieurs points
  • Point : une structure contenant ; informations de latitude et de longitude ;
  • Demande du client : contenant les informations sur l'adresse de l'utilisateur.

Ensuite, nous pouvons implémenter cette fonction selon les idées de conception suivantes :

  • Utiliser un service API de carte pour obtenir les informations géographiques de la zone du polygone et stocker ces informations dans un tableau
  • Analyser la demande du client, obtenir ; les informations géographiques de l'emplacement du client ;
  • Utilisez l'algorithme de polygone pour déterminer si l'emplacement du client est dans la plage de service et donner le résultat de réponse correspondant.

En langage Go, nous pouvons utiliser la bibliothèque go-mapbox pour accéder au service API de carte. Dans le même temps, nous pouvons également utiliser la bibliothèque mathématique intégrée au langage Go pour implémenter des algorithmes de polygones. L'implémentation spécifique du code est la suivante :

package main

import (
    "fmt"
    "math"
    
    "github.com/ustroetz/go-mapbox"
)

type Point struct {
    Lat float64
    Lng float64
}

type Polygon []Point

func (p Point) ToCoordinates() *mapbox.Coordinates {
    return &mapbox.Coordinates{
        Longitude: p.Lng,
        Latitude:  p.Lat,
    }
}

func ContainsPointInPolygon(point Point, polygon Polygon) bool {
    intersectCount := 0
    polygonLength := len(polygon)

    if polygonLength < 3 {
        return false
    }

    endPoint := Point{Lat: 9999.0, Lng: point.Lng}

    for i := 0; i < len(polygon); i++ {
        startPoint := polygon[i]
        nextPointIndex := (i + 1) % len(polygon)
        nextPoint := polygon[nextPointIndex]

        if startPoint.Lng == nextPoint.Lng && endPoint.Lng == startPoint.Lng && (point.Lng == startPoint.Lng && (point.Lat > startPoint.Lat) == (point.Lat < endPoint.Lat)) {
            return true
        }

        if point.Lng > math.Min(startPoint.Lng, nextPoint.Lng) && point.Lng <= math.Max(startPoint.Lng, nextPoint.Lng) {
            deltaLat := nextPoint.Lat - startPoint.Lat
            if deltaLat == 0 {
                continue
            }
            intersectLat := startPoint.Lat + (point.Lng-startPoint.Lng)*(nextPoint.Lat-startPoint.Lat)/(nextPoint.Lng-startPoint.Lng)
            if intersectLat == point.Lat {
                return true
            }
            if intersectLat > point.Lat {
                intersectCount++
            }
        }
    }

    return intersectCount%2 != 0
}

func InDeliveryArea(point Point, apiKey string) bool {
    client := mapbox.New(apiKey)

    // 可以使用自己的多边形坐标
    geojson, _, _ := client.MapMatching().GetMapMatching(
        []mapbox.Coordinates{
            *point.ToCoordinates(),
        },
           nil,
    )
    polygon := geojson.Features[0].Geometry.Coordinates[0].([]interface{})
    var polygonArray Polygon
    for _, item := range polygon {
        arr := item.([]interface{})
        p := Point{Lat: arr[1].(float64), Lng: arr[0].(float64)}
        polygonArray = append(polygonArray, p)
    }
    fmt.Println("多边形坐标: ", polygonArray)

    return ContainsPointInPolygon(point, polygonArray)
}

func main() {
    point := Point{
        Lat: 31.146922,
        Lng: 121.362282,
    }

    apiKey := "YOUR_ACCESS_TOKEN"

    result := InDeliveryArea(point, apiKey)

    fmt.Println("坐标是否在配送范围内:", result)
}

Ce qui précède est un exemple de code d'implémentation de base du langage Go. Avant d'exécuter ce code, vous devez d'abord obtenir un jeton d'accès à partir de l'arrière-plan de l'API de la carte. Remplacez simplement YOUR_ACCESS_TOKEN par Token. De plus, vous devez également saisir les coordonnées correspondantes et les paramètres associés dans l'interface de requête de polygone fournie par l'API de carte. En exécutant le code ci-dessus, vous pouvez obtenir une valeur booléenne indiquant si l'emplacement des coordonnées se trouve dans la plage de service. YOUR_ACCESS_TOKEN即可。另外,还需要在地图API提供的多边形查询接口中输入对应的坐标和相关参数。运行以上代码,可以得到一个代表坐标所在位置是否在服务范围内的布尔值。

  1. 封装成为可复用库

上述示例代码可以帮助我们完成外卖点餐系统的外卖配送范围功能。但是,在实际应用中,这个功能可能被多个页面或模块所使用。为了避免重复编写代码的麻烦,我们需要将其封装成为一个可复用的库。具体而言:

  • 我们可以将上述的InDeliveryArea函数封装成为一个可以从外部调用的函数。
  • 另外,我们还可以对外部输入的参数进行检查和校验,以保证程序的健壮性。

例如,我们可以将代码重新组织,把获取多边形和判断点在多边形内两个操作分离,这样也方便后续扩展。

以下是Go语言封装成为可复用库的示例代码:

package delivery

import (
    "fmt"
    "math"
    
    "github.com/ustroetz/go-mapbox"
)

type Point struct {
    Lat float64
    Lng float64
}

type Polygon []Point

type DeliveryArea struct {
    polygon Polygon
    client  *mapbox.Client
}

func NewDeliveryArea(apiKey string, polygonArray []Point) *DeliveryArea {
    client := mapbox.New(apiKey)

    var polygon Polygon
    for _, p := range polygonArray {
        polygon = append(polygon, p)
    }

    return &DeliveryArea{polygon: polygon, client: client}
}

func (p Point) ToCoordinates() *mapbox.Coordinates {
    return &mapbox.Coordinates{
        Longitude: p.Lng,
        Latitude:  p.Lat,
    }
}

func (d *DeliveryArea) containsPoint(point Point) bool {
    intersectCount := 0
    polygonLength := len(d.polygon)

    if polygonLength < 3 {
        return false
    }

    endPoint := Point{Lat: 9999.0, Lng: point.Lng}

    for i := 0; i < len(d.polygon); i++ {
        startPoint := d.polygon[i]
        nextPointIndex := (i + 1) % len(d.polygon)
        nextPoint := d.polygon[nextPointIndex]

        if startPoint.Lng == nextPoint.Lng && endPoint.Lng == startPoint.Lng && (point.Lng == startPoint.Lng && (point.Lat > startPoint.Lat) == (point.Lat < endPoint.Lat)) {
            return true
        }

        if point.Lng > math.Min(startPoint.Lng, nextPoint.Lng) && point.Lng <= math.Max(startPoint.Lng, nextPoint.Lng) {
            deltaLat := nextPoint.Lat - startPoint.Lat
            if deltaLat == 0 {
                continue
            }
            intersectLat := startPoint.Lat + (point.Lng-startPoint.Lng)*(nextPoint.Lat-startPoint.Lat)/(nextPoint.Lng-startPoint.Lng)
            if intersectLat == point.Lat {
                return true
            }
            if intersectLat > point.Lat {
                intersectCount++
            }
        }
    }

    return intersectCount%2 != 0
}

func (d *DeliveryArea) Contains(point Point) bool {
    resp, _, err := d.client.MapMatching().GetMapMatching(
        []mapbox.Coordinates{
            *point.ToCoordinates(),
        },
           nil,
    )
    if err != nil {
        fmt.Printf("MapMatching error: %s
", err)
        return false
    }
    geojson := resp.Features[0].Geometry.Coordinates[0].([]interface{})

    var polygonArray Polygon
    for _, item := range geojson {
        arr := item.([]interface{})
        p := Point{Lat: arr[1].(float64), Lng: arr[0].(float64)}
        polygonArray = append(polygonArray, p)
    }

    return d.containsPoint(point)
}

这里我们使用了工厂模式来创建DeliveryArea结构体,可以看到,除了方便使用外,还可以发现它们的内部逻辑相对清晰,继而更易于维护。如下是一个使用上述封装后库的示例代码:

package main

import (
    "fmt"

    "github.com/username/repo_deliver_area/delivery"
)

func main() {
    polygonArray := []delivery.Point{
        {Lat: 31.23039, Lng: 121.4737},
        {Lat: 31.23886, Lng: 121.50016},
        {Lat: 31.19394, Lng: 121.5276},
        {Lat: 31.18667, Lng: 121.49978},
    }

    apiKey := "YOUR_ACCESS_TOKEN"

    deliveryArea := delivery.NewDeliveryArea(apiKey, polygonArray)

    point := delivery.Point{
        Lat: 31.146922,
        Lng: 121.362282,
    }

    result := deliveryArea.Contains(point)

    fmt.Println(result)
}

在运行这段代码之前,需要先将库文件放置到指定位置,并替换掉Import路径中的username/repo_deliver_area,以及将地图API的Access Token替换掉 YOUR_ACCESS_TOKEN

    Encapsulé dans une bibliothèque réutilisable🎜🎜🎜L'exemple de code ci-dessus peut nous aider à compléter la fonction de plage de livraison à emporter du système de commande à emporter. Cependant, dans les applications réelles, cette fonctionnalité peut être utilisée par plusieurs pages ou modules. Afin d'éviter d'avoir à écrire du code à plusieurs reprises, nous devons l'encapsuler dans une bibliothèque réutilisable. Plus précisément : 🎜🎜🎜Nous pouvons encapsuler la fonction InDeliveryArea ci-dessus dans une fonction qui peut être appelée de l'extérieur. 🎜🎜De plus, nous pouvons également vérifier et vérifier les paramètres d'entrée externes pour garantir la robustesse du programme. 🎜🎜🎜Par exemple, nous pouvons réorganiser le code et séparer les deux opérations d'obtention de polygones et de jugement des points à l'intérieur des polygones, ce qui facilitera également l'expansion ultérieure. 🎜🎜Ce qui suit est un exemple de code qui encapsule le langage Go dans une bibliothèque réutilisable : 🎜rrreee🎜Ici, nous utilisons le modèle d'usine pour créer la structure DeliveryArea. Comme vous pouvez le voir, en plus d'être pratique à utiliser, vous pouvez également trouver. que leur logique interne est relativement claire, ce qui facilite la maintenance. Voici un exemple de code utilisant la bibliothèque encapsulée ci-dessus : 🎜rrreee🎜 Avant d'exécuter ce code, vous devez placer le fichier de bibliothèque à l'emplacement spécifié et remplacer username/repo_deliver_area dans le chemin d'importation. le Token d'Accès de l'API cartographique avec YOUR_ACCESS_TOKEN. Le résultat final sera une valeur booléenne indiquant si l'emplacement des coordonnées se trouve dans la plage de service. 🎜

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn