Использовать MySQL WKB геометрию на iOS для MapKit - PullRequest
0 голосов
/ 23 апреля 2011

Я знаю, как преобразовать геометрию MySQL из двоичного файла в текст, а затем передать / преобразовать ее для использования в MapKit. Однако это кажется излишне неэффективным. Я ищу способ передачи бинарных фигур (например, полигонов) их родственникам Mapkit (например, MkPolygon) с учетом эффективности использования полосы пропускания.

Есть ли способ напрямую потреблять эти двоичные формы и конвертировать в iOS? Достаточно ли легко разобрать двоичный формат? Я хотел бы избегать преобразования в текст, а затем обратно в двоичный файл, пока он не будет, по крайней мере, на мобильном устройстве, чтобы избежать раздувания по сети передачи миллионов чисел с плавающей запятой двойной точности, отображаемых в виде символьных строк.

Я нашел ShapeKit Майкла Вейсмана на GitHub, который берет геометрию GEOS и выплевывает объекты MapKit. Однако ShapeKit полагается на WKT в качестве отправной точки, если у вас нет полностью созданного экземпляра объекта GEOS. Поэтому я взломал его, чтобы построить геометрию GEOS из байтов WKB (путем помещения данных MySQL WKB в NSData), но кажется, что двоичный файл, возвращаемый из MySQL, не совсем то, что он ожидал. Возможно, есть проблема с порядком байтов ...?

@implementation ShapeKitGeometry
@synthesize wktGeom,geomType, projDefinition ,geosGeom, numberOfCoords;

- (id) init
{
    self = [super init];
    if (self != nil) {
        // initialize GEOS library
        handle = initGEOS_r(notice, log_and_exit);
    }
    return self;
}

-(id)initWithWKB:(const unsigned char *) wkb size:(size_t)wkb_size {
    [self init];
    GEOSWKBReader *WKBReader = GEOSWKBReader_create_r(handle);
    self.geosGeom = GEOSWKBReader_read_r(handle, WKBReader, wkb, wkb_size);
    GEOSWKBReader_destroy_r(handle, WKBReader);
    self.geomType = [NSString stringWithUTF8String:GEOSGeomType_r(handle, geosGeom)];
    return self;
}

// .... later in my appDelegate:
- (ShapeKitPolygon *)loadWKBPolygonFromFile:(NSString *)file {
    ShapeKitPolygon * poly = nil;
    NSString *path = [[NSBundle mainBundle] pathForResource:file ofType:@"plist"];
    NSDictionary *stupidDict = [NSDictionary dictionaryWithContentsOfFile:path];
    NSData *geomData = [stupidDict objectForKey:@"shape"];
    if (geomData && [geomData length]) {
        poly = [[[ShapeKitPolygon alloc] initWithWKB:[geomData bytes] size:[geomData length]] autorelease];
    }
    return poly;
}

Мысли

Ответы [ 2 ]

0 голосов
/ 26 апреля 2011

Я понял это. Начиная с ShapeKit Майкла Вейсмана (как отмечалось в первоначальном вопросе), я создал несколько дополнительных методов, которые будут анализировать двоичные многоугольники WKB (включая любые внутренние кольца или «дыры») и выплевывать соответствующий MKPolygon, подходящий для MapKit.

Проблема решена ....

 /* make sure you grab your Polygon data column from MySQL with the following:
    "select AsBinary(shapeColumn) from tableName;"


  .... add the first three methods found in the question to ShapeGeometry.mm 
    and your application's map view controller (the NSData usage example)

  ALSO, add this method further down in that file, for ShapeKitPolygon
*/

@implementation ShapeKitPolygon
@synthesize geometry;//,numberOfCoords;

-(id)initWithWKB:(const unsigned char *) wkb size:(size_t)wkb_size{
    size_t length = wkb_size;

    [super initWithWKB:wkb size:length];
    GEOSCoordSequence *sequence = nil;

    int numInteriorRings = GEOSGetNumInteriorRings_r(handle, geosGeom);
    NSMutableArray *interiors = [[NSMutableArray alloc] init];
    int interiorIndex = 0;
    for (interiorIndex = 0; interiorIndex< numInteriorRings; interiorIndex++) {
        const GEOSGeometry *interior = GEOSGetInteriorRingN_r(handle, geosGeom, interiorIndex);
        sequence = GEOSCoordSeq_clone_r(handle, GEOSGeom_getCoordSeq_r(handle, interior));
        unsigned int numCoordsInt = 0;
        GEOSCoordSeq_getSize_r(handle, sequence, &numCoordsInt); 
        CLLocationCoordinate2D coordsInt[numCoordsInt];
        for (int coord = 0; coord < numCoordsInt; coord++) {
            double xCoord = NULL;

            GEOSCoordSeq_getX_r(handle, sequence, coord, &xCoord);

            double yCoord = NULL;
            GEOSCoordSeq_getY_r(handle, sequence, coord, &yCoord);
            coordsInt[coord] = CLLocationCoordinate2DMake(yCoord, xCoord);
        }
        [interiors addObject:[MKPolygon polygonWithCoordinates:coordsInt count:numCoordsInt]];
        GEOSCoordSeq_destroy_r(handle, sequence);       
    }
    const GEOSGeometry *exterior = GEOSGetExteriorRing_r(handle, geosGeom);
    sequence = GEOSCoordSeq_clone_r(handle, GEOSGeom_getCoordSeq_r(handle, exterior));
    GEOSCoordSeq_getSize_r(handle, sequence, &numberOfCoords);
    CLLocationCoordinate2D coordsExt[numberOfCoords];
    for (int coord = 0; coord < numberOfCoords; coord++) {
        double xCoord = NULL;
        GEOSCoordSeq_getX_r(handle, sequence, coord, &xCoord);

        double yCoord = NULL;
        GEOSCoordSeq_getY_r(handle, sequence, coord, &yCoord);
        coordsExt[coord] = CLLocationCoordinate2DMake(yCoord, xCoord);
    }
    if ([interiors count])
        geometry = [MKPolygon polygonWithCoordinates:coordsExt count:numberOfCoords interiorPolygons:interiors];
    else
        geometry = [MKPolygon polygonWithCoordinates:coordsExt count:numberOfCoords];

    GEOSCoordSeq_destroy_r(handle, sequence);
    [interiors release];

    return self;
}
0 голосов
/ 23 апреля 2011

Не можете ли вы выбрать полигоны из сервера MySQL с помощью C API, а затем преобразовать их или эти расширения недоступны на iPhone?

с помощью: SELECT AsBinary (column_name) FROM table_name;

...