2014-09-12 5 views
0

В настоящее время я работаю над этим: я создаю файл .vtm Paraview, содержащий несколько .vtr-файлов. Каждый файл .vtr содержит значение и координаты, как это, предполагая, что я работаю над размерностью 8:Разделить трехмерную матрицу на более мелкие «кубы»

<PointData Scalars="U"> 
    <DataArray type="Float32" Name="U" format="ascii"> 
    <!-- 8*8*8 values --> 
    </DataArray> 
</PointData> 
<Coordinates> 
    <DataArray type="Float32" Name="x" format="ascii"> 
    <!-- 8 x values --> 
    </DataArray> 
    <DataArray type="Float32" Name="y" format="ascii"> 
    <!-- 8 y values --> 
    </DataArray> 
    <DataArray type="Float32" Name="z" format="ascii"> 
    <!-- 8 z values --> 
    </DataArray> 
</Coordinates> 

я использую quadridimensionnal массив для хранения своих значений: float ****tab с tab[s][x][y][z], где:

  • s - текущий шаг разделения. Он увеличивается каждый раз, когда я начинаю работать над следующим .vtr-файлом.
  • x, y, z значения.

Теперь вот что вызывает у меня проблемы: координаты, где я должен размещать эти точки, могут быть любыми. Он может быть постоянным (после шага, например 0, 0,1, 0,2 и т. Д.), Или нет.

Я хранил координаты в трех массивах: x[], y[], z[]. Моя цель - сократить набор значений на более мелкие кубики. Предположим, что я разделил свои значения на 8 файлов (2^3 файла), я должен получить правильные координаты для 8 маленьких кубов. И я не могу найти способ сделать это.

Я уверен, что мой выбор структур данных ужасен, может ли кто-нибудь помочь мне с этим?

EDIT:

Вот функция генерации моего четыре звезды массива:

float**** fill_array_random4d(int split, int size) 
{ 
    float**** ret; 
    ret = malloc(sizeof(float***) * split); 
    for (int i = 0; i < split; i++) 
    { 
    ret[i] = malloc(sizeof (float**) * size); 
    for (int j = 0; j < size; j++) 
    { 
     ret[i][j] = malloc(sizeof (float*) * size); 
     for (int k = 0; k < size; k++) 
     { 
     ret[i][j][k] = malloc(sizeof (float) * size); 
     for (int l = 0; l < size; l++) 
      ret[i][j][k][l] = rand() % 100; 
     } 
    } 
    } 

    return ret; 
} 

Это довольно простой материал. Сейчас я использую случайные значения. Вот как я создавать и заполнять мои x, y, z массивы:

float *x, *y, *z; 
    x = malloc(sizeof (float) * size); 
    y = malloc(sizeof (float) * size); 
    z = malloc(sizeof (float) * size); 
    for (int i = 0; i < size * split; i++) 
    x[i] = step * i; 
    for (int i = 0; i < size * split; i++) 
    y[i] = step * i; 
    for (int i = 0; i < size * split; i++) 
    z[i] = step * i; 

Это по-прежнему очень простой, и, наконец, здесь является функция печати координат в файле, после ВТК существующего формата:

void print_Coordinates(FILE *file, float *x, float *y, float *z, int size, int split) 
{ 
    fprintf(file, "  <Coordinates>\n"); 
    for (int i = 0; i < 3; i++) 
    { 
    const char *text1 = "  <DataArray type=\"Float32\" Name=\""; 
    const char *text2 = "\" format=\"ascii\">\n"; 
    fprintf(file, "%s%c%s", text1, 'x' + i, text2); 
    for (int j = 0; j < size; j++) 
    { 
     if (i == 0) 
     fprintf(file, "   %f\n", x[j]); 
     else if (i == 1) 
     fprintf(file, "   %f\n", y[j]); 
     else 
     fprintf(file, "   %f\n", z[j]); 
    } 
    fprintf(file, "  </DataArray>\n"); 
    } 
    fprintf(file, "  </Coordinates>\n"); 
} 

Итак, да, это не делает то, что я хочу вообще. Вот скриншот результата:

Все кубы находятся друг на друге. С кодом, который я использовал ранее, у меня было несколько кубов (по одному на файл), но они были выровнены по диагонали (что тоже плохо).

+0

А 4- звездный программист. Впечатляет. Очень хорошо. – Igor

+0

Не могли бы вы разместить пример кода, чтобы у нас было лучшее представление о том, что вы уже делаете? –

+0

@Igor Да, я знаю, что это отстой, но на данный момент это выглядело как хорошая идея. – Nepho

ответ

1

Как вы допустили, есть некоторые проблемы с вашей структурой данных:

  • Первое измерение s кажется Неконгруентно: Если структура данных включает оригинал и меньший куб? Это непросто сделать, потому что меньшие кубы имеют другие размеры.
  • У вас есть много отдельных данных: (случайные) данные, координаты и размеры массива. Чтобы представить куб, вам нужно отслеживать все это. Я рекомендую создать структуру для хранения соответствующих данных.
  • Нет ничего плохого в вашем подходе, чтобы представить трехмерный массив с тройным указателем, но дизайн приводит к множеству фрагментированных распределений.Многомерный массив с постоянными размерами, вероятно, лучше представлен как один «плоский» блок памяти.

я предлагаю две структуры:

typedef struct Cube Cube; 
typedef struct Axis Axis; 

struct Axis { 
    int n;    /* number of values */ 
    float *data;  /* graduation values */ 
}; 

struct Cube { 
    Axis *x, *y, *z; /* Axes of the cube */ 
    float *data;  /* x-major data */ 
}; 

"оси" хранит значения вдоль одной из осей. Сам куб не беспокоится о коде, связанном с осью, и просто передает его его осям из трех членов. «Куб» - это ваш объект данных. (В приведенной ниже реализации представление данных является x-major, что означает, что x-цикл является самым внешним, z-цикл является самым внутренним. Вы можете это сделать, заменив петли.)

Если у вас есть заполненный объект куба , вы можете извлечь суб-кубы, создав куб меньшего размера и скопировав соответствующие диапазоны данных из осей и из данных куба. Если вы хотите покрыть весь куб, вы можете извлекать и писать кубы по мере их перемещения или хранить в массиве кубов, например. Cube *small[8] для разделения пополам для каждого направления. (. Это было бы, как ваш оригинальный s индекс, только то, что каждый куб может иметь свое собственное измерение)

Реализация этого поведения с (addmittedly простой) тест main ниже:

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

typedef struct Cube Cube; 
typedef struct Axis Axis; 

struct Axis { 
    int n;    /* number of values */ 
    float *data;  /* graduation values */ 
}; 

struct Cube { 
    Axis *x, *y, *z; /* Axes of the cube */ 
    float *data;  /* x-major data */ 
}; 

/* 
*  Create a new axis with a constant step. 
*/ 
Axis *axis_new(int n, float start, float step) 
{ 
    Axis *axis = malloc(sizeof(*axis)); 
    float *p; 

    axis->n = n; 
    axis->data = malloc(n * sizeof(*axis->data)); 

    p = axis->data; 
    while (n--) { 
     *p = start; 
     start += step; 
     p++; 
    } 

    return axis; 
} 

/* 
*  Destroy and clean up axis 
*/ 
void axis_delete(Axis *axis) 
{ 
    if (axis) { 
     free(axis->data); 
     free(axis); 
    } 
} 

/* 
*  Write axis in XML format to given file 
*/ 
void axis_write(const Axis *axis, FILE *f, const char *name) 
{ 
    float *p = axis->data; 
    int n = axis->n; 

    fprintf(f, " <DataArray type=\"Float32\" " 
     "Name=\"%s\" format=\"ascii\">\n", name); 

    fprintf(f, " "); 
    while (n--) { 
     fprintf(f, " %g", *p++); 
    } 
    fprintf(f, "\n"); 
    fprintf(f, " </DataArray>\n"); 
} 

/* 
*  Create a new axis that is a sub-axis of orig. 
*/ 
Axis *axis_slice(const Axis *orig, int start, int len) 
{ 
    Axis *axis = axis_new(len, 0, 0); 
    memcpy(axis->data, orig->data + start, len * sizeof(*axis->data)); 

    return axis; 
} 



/* 
*  Create a cube of zero values for the given axes 
*/ 
Cube *cube_new(Axis *x, Axis *y, Axis *z) 
{ 
    Cube *cube = malloc(sizeof(*cube)); 
    int dim = x->n * y->n * z->n; 

    cube->x = x; 
    cube->y = y; 
    cube->z = z; 

    cube->data = malloc(dim * sizeof(*cube->data)); 

    return cube; 
} 

/* 
*  Destroy and clean up cube 
*/ 
void cube_delete(Cube *cube) 
{ 
    if (cube) { 
     axis_delete(cube->x); 
     axis_delete(cube->y); 
     axis_delete(cube->z); 

     free(cube->data); 
     free(cube); 
    } 
} 

float *cube_at(const Cube *cube, int x, int y, int z) 
{ 
    int pos = (x * cube->y->n + y) * cube->z->n + z; 
    return cube->data + pos; 
} 

/* 
*  Populate all x, y, z values according to the function func. 
*/ 
void cube_populate(Cube *cube, float (*func)(float x, float y, float z)) 
{ 
    int i, j, k; 
    float *p = cube->data; 

    for (i = 0; i < cube->x->n; i++) { 
     float x = cube->x->data[i]; 

     for (j = 0; j < cube->y->n; j++) { 
      float y = cube->y->data[j]; 

      for (k = 0; k < cube->z->n; k++) { 
       float z = cube->z->data[k]; 

       *p++ = func(x, y, z); 
      } 
     } 
    }  
} 

/* 
*  Write cube to given file. 
*/ 
void cube_write(const Cube *cube, FILE *f) 
{ 
    float *p = cube->data; 
    int n = cube->x->n * cube->y->n * cube->z->n; 

    fprintf(f, "<PointData Scalars=\"U\">\n"); 
    fprintf(f, " <DataArray type=\"Float32\" Name=\"U\" format=\"ascii\">\n"); 

    while (n--) { 
     fprintf(f, " %g", *p++); 
    } 
    fprintf(f, "\n"); 

    fprintf(f, " </DataArray>\n"); 
    fprintf(f, "</PointData>\n"); 

    fprintf(f, "<Coordinates>\n"); 
    axis_write(cube->x, f, "x"); 
    axis_write(cube->y, f, "y"); 
    axis_write(cube->z, f, "z"); 
    fprintf(f, "</Coordinates>\n"); 
} 

/* 
*  Create a new cube that is a sub-cube of orig. 
*/ 
Cube *cube_slice(const Cube *orig, 
    int x, int dx, int y, int dy, int z, int dz) 
{ 
    Cube *cube; 
    float *p; 
    int i, j, k; 

    if (x + dx > orig->x->n) return NULL; 
    if (y + dy > orig->y->n) return NULL; 
    if (z + dz > orig->z->n) return NULL; 

    cube = cube_new(
     axis_slice(orig->x, x, dx), 
     axis_slice(orig->y, y, dy), 
     axis_slice(orig->z, z, dz)); 

    p = cube->data; 

    for (i = 0; i < dx; i++) { 
     for (j = 0; j < dy; j++) { 
      for (k = 0; k < dz; k++) { 
       *p++ = *cube_at(orig, x + i, y + j, z + k); 
      } 
     } 
    }  

    return cube; 
} 

/* 
*  Example appliaction 
*/ 
float dist2(float x, float y, float z) 
{ 
    return x*x + y*y + z*z; 
} 

int main() 
{ 
    Cube *cube = cube_new(
     axis_new(4, 0, 0.1), 
     axis_new(4, 0, 0.1), 
     axis_new(4, 0, 0.1)); 
    int i, j, k; 

    cube_populate(cube, dist2); 

    for (i = 0; i < 2; i++) { 
     for (j = 0; j < 2; j++) { 
      for (k = 0; k < 2; k++) { 
       Cube *sub = cube_slice(cube, 2*i, 2, 2*j, 2, 2*k, 2); 

       cube_write(sub, stdout); 
       printf("--\n"); 
       cube_delete(sub); 
      } 
     } 
    } 

    cube_delete(cube); 

    return 0; 
} 
+0

Спасибо за ваш вклад, я получил свой код для работы, но я обязательно проверю ваше решение и реализую его, так как у меня действительно плебейский уровень. – Nepho

+0

Я кое-что не понимаю. В функции cube_new вы выделяете некоторое пространство для данных cube->, но не заполняете его. Тем не менее, вы используете это поле позже ... Не могли бы вы объяснить, пожалуйста? – Nepho

+0

О, ладно, я понял. Ось содержит только координаты. Куб содержит все значения в поле «данные». Благодаря ! – Nepho