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.
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 :
Afin de mettre en œuvre cette fonction, nous devons utiliser certains outils et technologies :
Avant d'implémenter cette fonction, nous devons définir quelques structures de données et interfaces de base :
Ensuite, nous pouvons implémenter cette fonction selon les idées de conception suivantes :
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提供的多边形查询接口中输入对应的坐标和相关参数。运行以上代码,可以得到一个代表坐标所在位置是否在服务范围内的布尔值。
上述示例代码可以帮助我们完成外卖点餐系统的外卖配送范围功能。但是,在实际应用中,这个功能可能被多个页面或模块所使用。为了避免重复编写代码的麻烦,我们需要将其封装成为一个可复用的库。具体而言:
例如,我们可以将代码重新组织,把获取多边形和判断点在多边形内两个操作分离,这样也方便后续扩展。
以下是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
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!