2023-07-10 02:42:26 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
|
|
|
|
* Change Logs:
|
|
|
|
|
* Date Author Notes
|
|
|
|
|
* 2023-06-24 murmur the first version
|
|
|
|
|
*/
|
|
|
|
|
/**
|
|
|
|
|
* 本函数通过geojson文件构建电子围栏,并判别是否在围栏内
|
|
|
|
|
* 解析geojson文件,获取多边形经纬度
|
|
|
|
|
* 判断当前坐标是否在多边形内部
|
|
|
|
|
*/
|
|
|
|
|
#include <rtthread.h>
|
|
|
|
|
|
|
|
|
|
#define LOG_TAG "map"
|
2023-08-22 10:23:41 +00:00
|
|
|
|
#define LOG_LVL LOG_LVL_INFO
|
2023-07-10 02:42:26 +00:00
|
|
|
|
#include <ulog.h>
|
|
|
|
|
|
|
|
|
|
#include <dfs_file.h>
|
|
|
|
|
#include <cJSON.h>
|
|
|
|
|
|
|
|
|
|
/** .geojson文件
|
|
|
|
|
{
|
|
|
|
|
"type":"FeatureCollection",
|
|
|
|
|
"features":[
|
|
|
|
|
{
|
|
|
|
|
"type":"Feature",
|
|
|
|
|
"properties":{
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
"geometry":{
|
|
|
|
|
"coordinates":[
|
|
|
|
|
[
|
|
|
|
|
[
|
|
|
|
|
109.84662252076487,
|
|
|
|
|
18.40384100935684
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.84827972641727,
|
|
|
|
|
18.391934106424912
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.86043256475983,
|
|
|
|
|
18.391829269588243
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.86800046865523,
|
|
|
|
|
18.396651709843837
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.86811094900406,
|
|
|
|
|
18.41132787117354
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.85225701894615,
|
|
|
|
|
18.41284783067367
|
|
|
|
|
],
|
|
|
|
|
[
|
|
|
|
|
109.84662252076487,
|
|
|
|
|
18.40384100935684
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
],
|
|
|
|
|
"type":"Polygon"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析电子围栏的各顶点
|
|
|
|
|
* @param fin 电子围栏文件,标准*.geojson文件,可通过http://geojson.io/获取
|
|
|
|
|
* @param *x 用于存储经度的数组
|
|
|
|
|
* @param *y 由于存储纬度的数组
|
|
|
|
|
* @return 顶点个数
|
|
|
|
|
*/
|
|
|
|
|
int mapParse(const char *fin,float *x, float *y)
|
|
|
|
|
{
|
|
|
|
|
cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
|
|
|
|
|
|
|
|
|
|
int fd_in = -1;
|
|
|
|
|
int rst=-RT_ERROR;
|
|
|
|
|
fd_in = open(fin, O_RDONLY, 0);
|
|
|
|
|
if (fd_in < 0)
|
|
|
|
|
{
|
|
|
|
|
LOG_E("[hex] open the input file : %s error.", fin);
|
|
|
|
|
return rst;
|
|
|
|
|
}
|
|
|
|
|
size_t file_size = lseek(fd_in, 0, SEEK_END);
|
|
|
|
|
lseek(fd_in, 0, SEEK_SET);
|
|
|
|
|
|
|
|
|
|
rt_uint8_t *buffer = RT_NULL;
|
|
|
|
|
buffer = (rt_uint8_t *) rt_malloc(512);
|
|
|
|
|
read(fd_in, buffer, file_size);
|
|
|
|
|
close(fd_in);
|
|
|
|
|
// LOG_HEX("json",16,buffer,file_size);
|
|
|
|
|
|
|
|
|
|
root = cJSON_Parse((const char *) buffer);
|
|
|
|
|
if (!root)
|
|
|
|
|
{
|
|
|
|
|
LOG_W("No memory for cJSON root!");
|
|
|
|
|
goto _exit;
|
|
|
|
|
}
|
|
|
|
|
//坐标所在层级为 root->features[0]->geometry->coordinates[0]
|
|
|
|
|
object = cJSON_GetObjectItem(root, "features");
|
|
|
|
|
if (cJSON_IsArray(object))
|
|
|
|
|
{
|
|
|
|
|
// LOG_D("size of 'features' is %d",cJSON_GetArraySize(object));
|
2023-08-25 00:08:30 +00:00
|
|
|
|
cJSON *tmp = cJSON_GetArrayItem(object, 0);
|
|
|
|
|
item = cJSON_GetObjectItem(tmp, "geometry");
|
2023-07-10 02:42:26 +00:00
|
|
|
|
if (item)
|
|
|
|
|
{
|
|
|
|
|
cJSON *sitem = cJSON_GetObjectItem(item, "type");
|
|
|
|
|
// LOG_D("type is %s",sitem->valuestring);
|
|
|
|
|
if (rt_strcmp(sitem->valuestring,"Polygon") != 0)
|
|
|
|
|
{
|
|
|
|
|
LOG_E("type is not match, needed to be 'Polygon'");
|
|
|
|
|
goto _exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sitem = cJSON_GetObjectItem(item, "coordinates");
|
|
|
|
|
if (cJSON_IsArray(sitem))
|
|
|
|
|
{
|
2023-08-25 00:08:30 +00:00
|
|
|
|
cJSON *tmp2 = cJSON_GetArrayItem(sitem, 0);
|
|
|
|
|
if (cJSON_IsArray(tmp2))
|
2023-07-10 02:42:26 +00:00
|
|
|
|
{
|
2023-08-25 00:08:30 +00:00
|
|
|
|
size_t cnt = cJSON_GetArraySize(tmp2)-1;//最后一个是重复的
|
2023-07-10 02:42:26 +00:00
|
|
|
|
LOG_D("cnt of 'coordinates' pairs is %d", cnt);
|
|
|
|
|
if (cnt<3) {//至少是个三角形
|
|
|
|
|
rst = -RT_ERROR;
|
|
|
|
|
LOG_W("cnt of 'coordinates' pairs is too few.");
|
|
|
|
|
goto _exit;
|
|
|
|
|
}
|
|
|
|
|
for (size_t var = 0; var < cnt; var++)
|
|
|
|
|
{
|
2023-08-25 00:08:30 +00:00
|
|
|
|
cJSON *llp = cJSON_GetArrayItem(tmp2, var);
|
|
|
|
|
if (cJSON_IsArray(llp))
|
2023-07-10 02:42:26 +00:00
|
|
|
|
{
|
|
|
|
|
float lon = cJSON_GetNumberValue(cJSON_GetArrayItem(llp, 0)); //经度
|
|
|
|
|
x[var]= lon;
|
|
|
|
|
float lat = cJSON_GetNumberValue(cJSON_GetArrayItem(llp, 1)); //维度
|
|
|
|
|
y[var]= lat;
|
2023-08-22 10:23:41 +00:00
|
|
|
|
LOG_D("%lf-%lf", x[var], y[var]);
|
2023-07-10 02:42:26 +00:00
|
|
|
|
rst = cnt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_exit:
|
|
|
|
|
cJSON_Delete(root);
|
|
|
|
|
rt_free(buffer);
|
|
|
|
|
return rst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Globals which should be set before calling this function:
|
|
|
|
|
//
|
|
|
|
|
// int polyCorners = how many corners the polygon has
|
|
|
|
|
// float polyX[] = horizontal coordinates of corners
|
|
|
|
|
// float polyY[] = vertical coordinates of corners
|
|
|
|
|
// float x, y = point to be tested
|
|
|
|
|
//
|
|
|
|
|
// (Globals are used in this example for purposes of speed. Change as
|
|
|
|
|
// desired.)
|
|
|
|
|
//
|
|
|
|
|
// The function will return YES if the point x,y is inside the polygon, or
|
|
|
|
|
// NO if it is not. If the point is exactly on the edge of the polygon,
|
|
|
|
|
// then the function may return YES or NO.
|
|
|
|
|
//
|
|
|
|
|
// Note that division by zero is avoided because the division is protected
|
|
|
|
|
// by the "if" clause which surrounds it.
|
|
|
|
|
/**
|
|
|
|
|
* 判断某点是否在多边形内部,移植至http://alienryderflex.com/polygon/
|
|
|
|
|
* @param polyCorners 多边形顶点个数
|
|
|
|
|
* @param polyX x坐标数组,对应经度
|
|
|
|
|
* @param polyY y坐标数组,对应纬度
|
|
|
|
|
* @param x 点的x坐标
|
|
|
|
|
* @param y 点的y坐标
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
int pointInPolygon(int polyCorners,float polyX[], float polyY[],float x,float y)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int i, j=polyCorners-1 ;
|
|
|
|
|
int oddNodes=0 ;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<polyCorners; i++) {
|
|
|
|
|
if ((polyY[i]< y && polyY[j]>=y
|
|
|
|
|
|| polyY[j]< y && polyY[i]>=y)
|
|
|
|
|
&& (polyX[i]<=x || polyX[j]<=x)) {
|
|
|
|
|
oddNodes^=(polyX[i]+(y-polyY[i])/(polyY[j]-polyY[i])*(polyX[j]-polyX[i])<x); }
|
|
|
|
|
j=i; }
|
|
|
|
|
|
|
|
|
|
return oddNodes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static demo(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
char *f = "/map.geojson";
|
|
|
|
|
if (argc == 2)
|
|
|
|
|
{
|
|
|
|
|
rt_strcpy(f,argv[1]);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-22 10:23:41 +00:00
|
|
|
|
float polyX[10]={},polyY[10]={};
|
2023-08-25 00:08:30 +00:00
|
|
|
|
// cmd_free();
|
2023-08-22 10:23:41 +00:00
|
|
|
|
int polyCorners = mapParse(f,polyX,polyY);
|
|
|
|
|
for (uint8_t var = 0; var < polyCorners; var++) {
|
2023-08-23 03:02:26 +00:00
|
|
|
|
LOG_I("%d=%d.%d,%d.%d",var+1,
|
|
|
|
|
(int)polyX[var],(int)((long)(polyX[var]*1000000) % 1000000),
|
|
|
|
|
(int)polyY[var],(int)((long)(polyY[var]*1000000) % 1000000));
|
2023-08-22 10:23:41 +00:00
|
|
|
|
}
|
2023-08-25 00:08:30 +00:00
|
|
|
|
// cmd_free();
|
2023-07-10 02:42:26 +00:00
|
|
|
|
}
|
2023-08-22 10:23:41 +00:00
|
|
|
|
MSH_CMD_EXPORT_ALIAS(demo,d_parseFence,解析围栏);
|