/* * 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 #define LOG_TAG "map" #define LOG_LVL LOG_LVL_INFO #include #include #include /** .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)); cJSON *tmp = cJSON_GetArrayItem(object, 0); item = cJSON_GetObjectItem(tmp, "geometry"); 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)) { cJSON *tmp2 = cJSON_GetArrayItem(sitem, 0); if (cJSON_IsArray(tmp2)) { size_t cnt = cJSON_GetArraySize(tmp2)-1;//最后一个是重复的 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++) { cJSON *llp = cJSON_GetArrayItem(tmp2, var); if (cJSON_IsArray(llp)) { float lon = cJSON_GetNumberValue(cJSON_GetArrayItem(llp, 0)); //经度 x[var]= lon; float lat = cJSON_GetNumberValue(cJSON_GetArrayItem(llp, 1)); //维度 y[var]= lat; LOG_D("%lf-%lf", x[var], y[var]); 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=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])