Хранение CLLocation2DCoordinates в массиве C - динамическая установка размера массива не работает

Я пытаюсь написать приложение, которое использует представление карты для добавления наложений. Данные оверлея загружаются из файла в NSArray, который выглядит следующим образом: ...

Revier355
int i = 0;
    NSArray *data = [self loadDatafromFile];
    NSMutableDictionary *overlays = [NSMutableDictionary new];
    for ( i=0; i<data.count;i++)
    {

        if ([[data objectAtIndex: i] isKindOfClass: [NSString class]])
            //start of new Polygon called Revier
        {
            //Name of Revier
            NSString *polyName = (NSString*)[data objectAtIndex: i];               
            //PointCount is second entry after name
            int noOfPoints = [[data objectAtIndex: (i+1)] intValue];                    
            //Revier coordinates Error while setting Array size dynamically
            CLLocationCoordinate2D *coord = malloc(sizeof(CLLocationCoordinate2D) * noOfPoints);                          
            for (int j=0; j<noOfPoints+1; j+=2)
                {

                    CLLocationCoordinate2D currCoord = CLLocationCoordinate2DMake([[data objectAtIndex:j+i] doubleValue],[[data objectAtIndex:j+i+1] doubleValue]);
                     coord[j] = currCoord;

                }
            MKPolygon *p = [MKPolygon polygonWithCoordinates:coord count:noOfPoints];
            [overlays setObject: p forKey:polyName];
            free(coord);
        }

    }
Poly, //name of the polygon (string) 6, //no of coordinates of polygon (int) 47.4038673907557, //latitude of first coordinate (double) 8.5247885145479, //longitude of first coordinate (double) 47.4035082236459, 8.52436382148047, 47.4031174379495, 8.52493568571008, 47.403348653295, 8.52586444637587, 47.4037666977377, 8.52550468311683, 47.4038673907557, 8.5247885145479

... следующий полигон с именем, количеством точек, координатами.

Теперь я хочу преобразовать приведенные выше данные в MKPolygons и поместить их в NSDictionary. Для этого я хочу создать массивы C, содержащие координаты каждого многоугольника в файле. Это требует динамической установки количества элементов в массиве во время выполнения. Вот моя проблема: у меня не получается это сделать. Не могли бы вы помочь или указать мне правильное направление?

Вот код, который я написал

int i = 0;
    NSArray *data = [self loadDatafromFile];
    NSMutableDictionary *overlays = [NSMutableDictionary new];
    for ( i=0; i<data.count;i++)
    {

        if ([[data objectAtIndex: i] isKindOfClass: [NSString class]])
            //start of new Polygon called Revier
        {
            //Name of Revier
            NSString *polyName = (NSString*)[data objectAtIndex: i];               
            //PointCount is second entry after name
            int noOfPoints = [[data objectAtIndex: (i+1)] intValue];                    
            //Revier coordinates Error while setting Array size dynamically
            CLLocationCoordinate2D *coord = malloc(sizeof(CLLocationCoordinate2D) * noOfPoints);                          
            for (int j=0; j<noOfPoints+1; j+=2)
                {

                    CLLocationCoordinate2D currCoord = CLLocationCoordinate2DMake([[data objectAtIndex:j+i] doubleValue],[[data objectAtIndex:j+i+1] doubleValue]);
                     coord[j] = currCoord;

                }
            MKPolygon *p = [MKPolygon polygonWithCoordinates:coord count:noOfPoints];
            [overlays setObject: p forKey:polyName];
            free(coord);
        }

    }

вот код загрузки данных...

- (NSArray *)loadDatafromFile
{
    NSArray* myArr = [[NSArray alloc] initWithContentsOfFile:[self filePath]];
    NSLog(@"%@",[self filePath]);
    return myArr;
}

- (NSString *) filePath
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"polygone" ofType:@"txt"];
    NSLog(@"%@",path);
    return path;

}

person user1612877    schedule 23.08.2012    source источник
comment
Я также попытался установить размер массива для координаты следующим образом: CLLocation2DCoordinate coord[noOfPoints]; однако это тоже не сработало.   -  person user1612877    schedule 24.08.2012
comment
Пожалуйста, добавьте код для -loadDatafromFile   -  person charliehorse55    schedule 24.08.2012
comment
Действительно ли ваш текстовый файл имеет формат, показанный на рисунке? Метод initWithContentsOfFile NSArray требует, чтобы файл был в формате plist (xml). Если вы хотите прочитать текстовый файл как есть, вам придется использовать метод NSString stringWithContentsOfFile, а затем вручную проанализировать строку, что является ненадежной и ненужной работой. Если вы поместите свои данные в формат plist, их будет намного проще прочитать в массиве словарей, которые затем можно легко использовать для создания объектов MKPolygon.   -  person    schedule 24.08.2012
comment
Спасибо за совет. Но данные уже в формате plist. То, что я разместил выше, было содержимым NSArray после загрузки plist. Однако, не могли бы вы дать немного больше информации о том, как использовать словарь для построения MKPolygons?   -  person user1612877    schedule 24.08.2012
comment
PS: Вот как выглядит начало plist, который я использую для загрузки данных: ‹?xml version=1.0 encoding=UTF-8?› ‹!DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN apple.com/DTDs/PropertyList-1.0.dtd› ‹plist version=1.0 › ‹array› ‹string›Revier1_Poly‹/string› ‹integer›204‹/integer› ‹real›47.22012717‹/real›‹real›8.808388347‹/real› ‹real›47.2394585400515‹/real.648‹/real.7488 настоящий>   -  person user1612877    schedule 24.08.2012
comment
Я не могу сейчас подробно ответить, но ваша проблема связана с внутренним циклом for j. Индексы, используемые для получения широты и долготы, неверны, индекс, используемый для установки координат [], неверен, j<noOfPoints+1 неверен (должен быть j < (noOfPoints*2)). Но вся эта работа была бы устранена, если бы сам plist содержал массив словарей, которые вы создаете вручную.   -  person    schedule 24.08.2012
comment
Ха-ха. Так много ошибок. Спасибо, что указали на них. Думаю, я попробую предложенный подход с массивом словарей, сохраненных в plist. Однако я до сих пор не знаю, как построить MKPolygon из словаря. Мой первоначальный подход будет состоять в том, чтобы поместить один словарь в словарь, поместить словарь в массив и сохранить массив в файл. С этого момента я буду работать в обратном порядке, чтобы знать, как структурировать входной список для приложений.   -  person user1612877    schedule 25.08.2012
comment
Благодаря лучшему макету plist можно избежать большей части этой работы. Вам все равно нужно будет создать массив C во время выполнения из NSArray, который вы получите из plist. Однако, если вы планируете позже сохранить сам объект MKPolygon, я бы не рекомендовал этого делать. Я считаю, что вам придется переключиться на сохранение как NSData. Вместо этого используйте объекты MKPolygon только во время выполнения, чтобы добавить их на карту. В противном случае просто работайте с plist-совместимыми объектами, такими как массивы, словари, NSNumbers и т. д.   -  person    schedule 25.08.2012
comment
На самом деле, я не хочу сохранять какие-либо MKPolygon во время выполнения. Тем не менее, я ищу способ загрузить полигоны, которые я хочу отображать в приложении, из файла. Я не собираюсь манипулировать никакими полигонами в приложении — они будут только отображаться. Есть ли лучший механизм для этого, чем plist?   -  person user1612877    schedule 28.08.2012


Ответы (1)


Во-первых, вот проблемы с вашим существующим кодом, который вручную анализирует отдельные элементы как один большой плоский массив...

Цикл for j имеет следующие проблемы:

  • j<noOfPoints+1 должно быть j < (noOfPoints*2), поскольку для каждой точки необходимо обработать два элемента массива.
  • Индексы для получения широты и долготы из массива data неверны (в строке, которая устанавливает currCoord). Кстати, эту строку было бы гораздо легче читать, понимать и (что особенно важно) отлаживать, если бы она была разбита на несколько операторов. Исправленный код может выглядеть так:

    int latitudeIndex = j+i +2;     //need to add additional offset of +2
    int longitudeIndex = j+i+1 +2;  //need to add additional offset of +2
    
    CLLocationDegrees lat = [[data objectAtIndex:latitudeIndex] doubleValue];
    CLLocationDegrees lon = [[data objectAtIndex:longitudeIndex] doubleValue];
    
    CLLocationCoordinate2D currCoord = CLLocationCoordinate2DMake(lat,lon);
    
  • Индекс, используемый для установки элемента в массиве C, неверен. В строке coord[j] = currCoord; j изначально будет 0, но затем увеличится на 2. Таким образом, вы в конечном итоге устанавливаете coord[0], coord[2] и т. д. и оставляете нечетные индексы неинициализированными. Вместо этого добавьте отдельный счетчик в качестве индекса для установки массива C (хотя его можно вычислить из j, отдельный счетчик чище и его легче понять или изменить):

    int coordIndex = 0;  //declare and initialize before the for-j loop
    for (int j=0;...
    {
        ...  //code to set currCoord
    
        coord[coordIndex] = currCoord;
        coordIndex++;
    }
    


Эти изменения должны исправить синтаксический анализ и создание полигональных объектов, но есть еще две общие проблемы:

  • Код вручную анализирует каждый отдельный элемент в массиве, что затрудняет написание, понимание и изменение.
  • Код в основном читает plist дважды, потому что внешний цикл должен прочитать элементы, которые уже обработаны внутренним циклом. Внешний цикл пропускает их, проверяя, является ли тип элемента строкой или нет.

Обе эти проблемы можно решить, используя лучший формат plist и позволяя встроенным методам чтения plist выполнять всю тяжелую работу за вас. Все, что вам нужно сделать, это создать массив C.

Вот возможный альтернативный формат plist для вас:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>PolygonName</key>
        <string>Revier355_2_Poly</string>
        <key>Coordinates</key>
        <array>
            <dict><key>Latitude</key><real>47.4038673907557</real><key>Longitude</key><real>8.5247885145479</real></dict>
            <dict><key>Latitude</key><real>47.4035082236459</real><key>Longitude</key><real>8.52436382148047</real></dict>
            <dict><key>Latitude</key><real>47.4031174379495</real><key>Longitude</key><real>8.52493568571008</real></dict>
            <dict><key>Latitude</key><real>47.403348653295</real><key>Longitude</key><real>8.52586444637587</real></dict>
            <dict><key>Latitude</key><real>47.4037666977377</real><key>Longitude</key><real>8.52550468311683</real></dict>
            <dict><key>Latitude</key><real>47.4038673907557</real><key>Longitude</key><real>8.5247885145479</real></dict>
        </array>
    </dict>
    <dict>
        <key>PolygonName</key>
        <string>Revier1_Poly</string>
        <key>Coordinates</key>
        <array>
            <dict><key>Latitude</key><real>47.22012717</real><key>Longitude</key><real>8.808388346999999</real></dict>
            <dict><key>Latitude</key><real>47.2394585400515</real><key>Longitude</key><real>8.79568994231076</real></dict>
            <dict><key>Latitude</key><real>47.1394585400515</real><key>Longitude</key><real>4.89568994231076</real></dict>
        </array>
    </dict>
</array>
</plist>

Код для чтения этого списка будет примерно таким:

NSArray *polygonsArray = [NSArray arrayWithContentsOfFile:path];

NSMutableDictionary *overlays = [NSMutableDictionary new];

//loop through the polygon dictionaries...
for (NSDictionary *polygonDict in polygonsArray) 
{
    NSString *polyName = [polygonDict objectForKey:@"PolygonName"];
    NSArray *coordDictionaries = [polygonDict objectForKey:@"Coordinates"];

    //loop through the array of coordinate dictionaries for the 
    //current polygon to create C array of coordinates...
    int noOfPoints = coordDictionaries.count;
    CLLocationCoordinate2D *coord = malloc(sizeof(CLLocationCoordinate2D) * noOfPoints);

    int coordIndex = 0;
    for (NSDictionary *coordDict in coordDictionaries) 
    {
        CLLocationDegrees lat = [[coordDict objectForKey:@"Latitude"] doubleValue];
        CLLocationDegrees lon = [[coordDict objectForKey:@"Longitude"] doubleValue];
        CLLocationCoordinate2D currCoord = CLLocationCoordinate2DMake(lat,lon);
        coord[coordIndex] = currCoord;
        coordIndex++;
    }

    MKPolygon *p = [MKPolygon polygonWithCoordinates:coord count:noOfPoints];
    [overlays setObject:p forKey:polyName];
    [self.mapView addOverlay:p];
    free(coord);
}

Обратите внимание, что единственный расчет индекса, с которым вам придется иметь дело, касается массива C.

Если вам нужен более продвинутый или стандартизированный формат, вы также можете посмотреть KML. Существует также пример приложения KMLViewer от Apple. Я думаю, что пример кода анализирует только полилинии.

По вашему вопросу в комментариях:

Есть ли лучший механизм для этого, чем plist?

Это зависит от того, сколько данных вы собираетесь хранить. Если plist недостаточно быстр для вашего приложения, вам придется переключиться на метод, обеспечивающий произвольный доступ к данным (например, базу данных SQL или несколько plist). Это, вероятно, стоит отдельного вопроса, если это необходимо.

person Community    schedule 27.08.2012
comment
Спасибо за этот отличный, подробный ответ. Я займусь этим. Что касается количества данных/полигонов, которые я собираюсь обработать: по моим оценкам, это будет около 500 полигонов. Поэтому я надеюсь, что подход plist должен быть осуществим. - person user1612877; 28.08.2012