+ ZDDecodePoint(point, &diffLat, &diffLon);
+ if(reader->referenceDirection < 0) {
+ diffLat = -diffLat;
+ diffLon = -diffLon;
+ }
+ }
+ }
+
+ if(reader->library->version == 0) {
+ if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLat)) return -1;
+ if(!ZDDecodeVariableLengthSigned(reader->library, &reader->polygonIndex, &diffLon)) return -1;
+ }
+
+ if(!reader->done) {
+ reader->pointLat += diffLat;
+ reader->pointLon += diffLon;
+ if(reader->first) {
+ reader->firstLat = reader->pointLat;
+ reader->firstLon = reader->pointLon;
+ }
+ } else {
+ /* Close the polygon (the closing point is not encoded) */
+ reader->pointLat = reader->firstLat;
+ reader->pointLon = reader->firstLon;
+ reader->done = 2;
+ }
+
+ reader->first = 0;
+
+ if(reader->library->version == 0) {
+ reader->numVertices--;
+ if(!reader->numVertices) {
+ reader->done = 1;
+ }
+ if(!diffLat && !diffLon) {
+ goto readNewPoint;
+ }
+ }
+
+ if(referenceDone) {
+ reader->referenceDirection = 0;
+ }
+
+ if(pointLat) {
+ *pointLat = reader->pointLat;
+ }
+
+ if(pointLon) {
+ *pointLon = reader->pointLon;
+ }
+
+ return 1;
+}
+
+static int ZDFindPolygon(const ZoneDetect *library, uint32_t wantedId, uint32_t* metadataIndexPtr, uint32_t* polygonIndexPtr)
+{
+ uint32_t polygonId = 0;
+ uint32_t bboxIndex = library->bboxOffset;
+
+ uint32_t metadataIndex = 0, polygonIndex = 0;
+
+ while(bboxIndex < library->metadataOffset) {
+ uint64_t polygonIndexDelta;
+ int32_t metadataIndexDelta;
+ int32_t tmp;
+ if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break;
+ if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break;
+ if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break;
+ if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &tmp)) break;
+ if(!ZDDecodeVariableLengthSigned(library, &bboxIndex, &metadataIndexDelta)) break;
+ if(!ZDDecodeVariableLengthUnsigned(library, &bboxIndex, &polygonIndexDelta)) break;
+
+ metadataIndex += (uint32_t)metadataIndexDelta;
+ polygonIndex += (uint32_t)polygonIndexDelta;
+
+ if(polygonId == wantedId) {
+ if(metadataIndexPtr) {
+ metadataIndex += library->metadataOffset;
+ *metadataIndexPtr = metadataIndex;
+ }
+ if(polygonIndexPtr) {
+ polygonIndex += library->dataOffset;
+ *polygonIndexPtr = polygonIndex;
+ }
+ return 1;
+ }
+
+ polygonId ++;
+ }
+
+ return 0;
+}
+
+static int32_t* ZDPolygonToListInternal(const ZoneDetect *library, uint32_t polygonIndex, size_t* length)
+{
+ struct Reader reader;
+ ZDReaderInit(&reader, library, polygonIndex);
+
+ size_t listLength = 2 * 100;
+ size_t listIndex = 0;
+
+ int32_t* list = malloc(sizeof(int32_t) * listLength);
+ if(!list) {
+ goto fail;
+ }
+
+ while(1) {
+ int32_t pointLat, pointLon;
+ int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon);
+ if(result < 0) {
+ goto fail;
+ } else if(result == 0) {
+ break;
+ }
+
+ if(listIndex >= listLength) {
+ listLength *= 2;
+ if(listLength >= 1048576) {
+ goto fail;
+ }
+
+ list = realloc(list, sizeof(int32_t) * listLength);
+ if(!list) {
+ goto fail;
+ }
+ }
+
+ list[listIndex++] = pointLat;
+ list[listIndex++] = pointLon;
+ }
+
+ if(length) {
+ *length = listIndex;
+ }
+
+ return list;
+
+fail:
+ if(list) {
+ free(list);
+ }
+ return NULL;
+}
+
+float* ZDPolygonToList(const ZoneDetect *library, uint32_t polygonId, size_t* lengthPtr)
+{
+ uint32_t polygonIndex;
+ int32_t* data = NULL;
+ float* flData = NULL;
+
+ if(!ZDFindPolygon(library, polygonId, NULL, &polygonIndex)) {
+ goto fail;
+ }
+
+ size_t length = 0;
+ data = ZDPolygonToListInternal(library, polygonIndex, &length);
+
+ if(!data) {
+ goto fail;
+ }
+
+ flData = malloc(sizeof(float) * length);
+ if(!flData) {
+ goto fail;
+ }
+
+ for(size_t i = 0; i<length; i+= 2) {
+ int32_t lat = data[i];
+ int32_t lon = data[i+1];
+
+ flData[i] = ZDFixedPointToFloat(lat, 90, library->precision);
+ flData[i+1] = ZDFixedPointToFloat(lon, 180, library->precision);
+ }
+
+ if(lengthPtr) {
+ *lengthPtr = length;
+ }
+
+ return flData;
+
+fail:
+ if(data) {
+ free(data);
+ }
+ if(flData) {
+ free(flData);
+ }
+ return NULL;
+}
+
+static ZDLookupResult ZDPointInPolygon(const ZoneDetect *library, uint32_t polygonIndex, int32_t latFixedPoint, int32_t lonFixedPoint, uint64_t *distanceSqrMin)
+{
+ int32_t pointLat, pointLon, prevLat = 0, prevLon = 0;
+ int prevQuadrant = 0, winding = 0;
+
+ uint8_t first = 1;
+
+ struct Reader reader;
+ ZDReaderInit(&reader, library, polygonIndex);
+
+ while(1) {
+ int result = ZDReaderGetPoint(&reader, &pointLat, &pointLon);
+ if(result < 0) {
+ return ZD_LOOKUP_PARSE_ERROR;
+ } else if(result == 0) {
+ break;