在 iOS 上为 MapKit 使用 MySQL WKB 几何图形

发布于 2024-11-03 02:48:03 字数 1770 浏览 1 评论 0原文

我知道如何将 MySQL 几何图形从二进制转换为文本,然后传输/转换它以在 MapKit 中使用。然而,这似乎效率低下,没有必要。我正在寻找一种将二进制形状(如多边形)传输到其 Mapkit 亲戚(如 MkPolygon)的方法,同时考虑到带宽效率。

有没有办法直接使用这些二进制形状并在 iOS 中进行转换? 二进制格式是否足够容易解析? 我想避免先转换为文本,然后再转换回二进制,直到至少在移动设备上,以避免传输数以百万计的双精度浮点数(表示为字符串)的网络膨胀。

我在 GitHub 上找到了 Michael Weismann 的 ShapeKit,它采用 GEOS 几何图形并输出 MapKit 对象。但是,ShapeKit 依赖 WKT 作为起点,除非您有完全实例化的 GEOS 对象。因此,我将其修改为从 WKB 字节构建 GEOS 几何(通过将 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;
}

想法?

I know how to convert MySQL geometry from binary to text and then transfer/convert it for use in MapKit. However, this seems unnecessarily inefficient. I'm looking for a way to transport the binary shapes (like polygons) to their Mapkit relatives (like MkPolygon) with bandwidth efficiency in mind.

Is there a way of directly consuming these binary shapes and converting in iOS?
Is the binary format sufficiently easy to parse?
I'd like to avoid converting to text then back to binary until it's at least on the mobile device, so as to avoid the network bloat of transmitting millions of double precision floats depicted as character strings.

I've found Michael Weismann's ShapeKit on GitHub, which takes GEOS geometry and spits out MapKit objects. However, ShapeKit relies on WKT as the starting point, unless you have a fully instantiated GEOS object. Therefore, I hacked it up to build GEOS geometry from WKB bytes (by way of stuffing the MySQL WKB data into NSData), but it seems like the binary returned from MySQL isn't quite what it was expecting. Perhaps there's an endian issue ... ?

@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;
}

Thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

信仰 2024-11-10 02:48:03

您不能使用 C API 从 MySQL 服务器中选择多边形,然后在那里进行转换吗?或者这些扩展在 iPhone 上不可用?

使用: SELECT AsBinary(column_name) FROM table_name;

Can't you select the polygons from the MySQL sever using the C API, then convert there, or are those extension's not available on the iPhone?

using: SELECT AsBinary(column_name) FROM table_name;

静谧 2024-11-10 02:48:03

我已经弄清楚了。从 Michael Weismann 的 ShapeKit(如最初问题中所述)开始,我制作了一些附加方法来解析 WKB 二进制多边形(包括任何内部环或“孔”)并吐出适合 MapKit 的适当 MKPolygon。

问题解决了....

 /* 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;
}

I've figured it out. Starting with Michael Weismann's ShapeKit (as noted in the initial question), I've crafted a few additional methods that will parse the WKB binary polygons (including any interior rings or "holes") and spit out the appropriate MKPolygon suitable for MapKit.

Problem solved....

 /* 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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文