/** * gwy_tip_erosion: * @tip: Tip data. * @surface: Surface to be eroded. * @result: Data field where to store dilated surface to. * @set_fraction: Function that sets fraction to output (or %NULL). * @set_message: Function that sets message to output (or %NULL). * * Performs surface reconstruction (erosion) algorithm published by * Villarrubia. This function converts all fields into form requested by * "morph_lib.c" library, that is almost identical with original Villarubia's * library. * * Returns: Reconstructed (eroded) surface, i.e. @result, on success. May * return %NULL if aborted. **/ GwyDataField* gwy_tip_erosion(GwyDataField *tip, GwyDataField *surface, GwyDataField *result, GwySetFractionFunc set_fraction, GwySetMessageFunc set_message) { gdouble **ftip; gdouble **fsurface; gdouble **fresult; GwyDataField *buffertip; gboolean freetip; /*if tip and surface have different spacings, make new, resampled tip*/ buffertip = get_right_tip_field(tip, surface, &freetip); /*invert tip (as necessary by dilation algorithm)*/ gwy_data_field_invert(buffertip, TRUE, TRUE, FALSE); /*make auxiliary data arrays expected by Villarubia's algorithms*/ ftip = datafield_to_field(buffertip, TRUE); fsurface = datafield_to_field(surface, FALSE); fresult = _gwy_morph_lib_derosion(fsurface, surface->yres, surface->xres, ftip, buffertip->yres, buffertip->xres, buffertip->yres/2, buffertip->xres/2, set_fraction, set_message); /*convert result back from auxiliary array*/ if (fresult) { gwy_data_field_resample(result, surface->xres, surface->yres, GWY_INTERPOLATION_NONE); result = field_to_datafield(fresult, result); } else result = NULL; /*free auxiliary data arrays*/ _gwy_morph_lib_dfreematrix(ftip, buffertip->xres); _gwy_morph_lib_dfreematrix(fsurface, surface->xres); if (fresult) _gwy_morph_lib_dfreematrix(fresult, result->xres); if (freetip) g_object_unref(buffertip); else gwy_data_field_invert(buffertip, TRUE, TRUE, FALSE); return result; }
static void rotate_180(GwyContainer *data, GwyRunType run) { GwyDataField *dfields[3]; GQuark quarks[3]; gint id; gint i; g_return_if_fail(run & BASICOPS_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, dfields + 0, GWY_APP_MASK_FIELD, dfields + 1, GWY_APP_SHOW_FIELD, dfields + 2, GWY_APP_DATA_FIELD_KEY, quarks + 0, GWY_APP_MASK_FIELD_KEY, quarks + 1, GWY_APP_SHOW_FIELD_KEY, quarks + 2, GWY_APP_DATA_FIELD_ID, &id, 0); clean_quarks(G_N_ELEMENTS(quarks), quarks, dfields); gwy_app_undo_qcheckpointv(data, G_N_ELEMENTS(quarks), quarks); for (i = 0; i < G_N_ELEMENTS(dfields); i++) { if (dfields[i]) { gwy_data_field_invert(dfields[i], TRUE, TRUE, FALSE); gwy_data_field_data_changed(dfields[i]); } } gwy_app_channel_log_add_proc(data, id, id); }
static void preview(DepositControls *controls, DepositArgs *args) { GwyDataField *dfield, *lfield, *zlfield, *zdfield; gint xres, yres, oxres, oyres; gint add, i, ii, m, k; gdouble size, width; gint xdata[10000]; gint ydata[10000]; gdouble disizes[10000]; gdouble rdisizes[10000]; gdouble rx[10000]; gdouble ry[10000]; gdouble rz[10000]; gdouble ax[10000]; gdouble ay[10000]; gdouble az[10000]; gdouble vx[10000]; gdouble vy[10000]; gdouble vz[10000]; gdouble fx[10000]; gdouble fy[10000]; gdouble fz[10000]; gint xpos, ypos, ndata, too_close; gdouble disize, mdisize; gdouble xreal, yreal, oxreal, oyreal; gdouble diff; gdouble mass = 1; gint presetval; gint nloc, maxloc = 1; gint max = 5000000; gdouble rxv, ryv, rzv, timestep = 3e-7; //5e-7 deposit_dialog_update_values(controls, args); dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(controls->mydata, "/0/data")); gwy_container_set_object_by_name(controls->mydata, "/0/data", gwy_data_field_duplicate(controls->old_dfield)); dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(controls->mydata, "/0/data")); if (controls->in_init) { gwy_data_field_data_changed(dfield); while (gtk_events_pending()) gtk_main_iteration(); return; } oxres = gwy_data_field_get_xres(dfield); oyres = gwy_data_field_get_yres(dfield); oxreal = gwy_data_field_get_xreal(dfield); oyreal = gwy_data_field_get_yreal(dfield); diff = oxreal/oxres/10; size = args->size*5e-9; // width = args->width*5e-9 + 2*size; //increased manually to fill boundaries width = 2*size; add = gwy_data_field_rtoi(dfield, size + width); mdisize = gwy_data_field_rtoi(dfield, size); xres = oxres + 2*add; yres = oyres + 2*add; xreal = oxreal + 2*(size+width); yreal = oyreal + 2*(size+width); // printf("For field of size %g and particle nominak %g, real %g (%g), the final size will change from %d to %d\n", // gwy_data_field_get_xreal(dfield), args->size, size, disize, oxres, xres); /*make copy of datafield, with mirrored boundaries*/ lfield = gwy_data_field_new(xres, yres, gwy_data_field_itor(dfield, xres), gwy_data_field_jtor(dfield, yres), TRUE); gwy_data_field_area_copy(dfield, lfield, 0, 0, oxres, oyres, add, add); gwy_data_field_invert(dfield, 1, 0, 0); gwy_data_field_area_copy(dfield, lfield, 0, oyres-add-1, oxres, add, add, 0); gwy_data_field_area_copy(dfield, lfield, 0, 0, oxres, add, add, yres-add-1); gwy_data_field_invert(dfield, 1, 0, 0); gwy_data_field_invert(dfield, 0, 1, 0); gwy_data_field_area_copy(dfield, lfield, oxres-add-1, 0, add, oyres, 0, add); gwy_data_field_area_copy(dfield, lfield, 0, 0, add, oyres, xres-add-1, add); gwy_data_field_invert(dfield, 0, 1, 0); gwy_data_field_invert(dfield, 1, 1, 0); gwy_data_field_area_copy(dfield, lfield, oxres-add-1, oyres-add-1, add, add, 0, 0); gwy_data_field_area_copy(dfield, lfield, 0, 0, add, add, xres-add-1, yres-add-1); gwy_data_field_area_copy(dfield, lfield, oxres-add-1, 0, add, add, 0, yres-add-1); gwy_data_field_area_copy(dfield, lfield, 0, oyres-add-1, add, add, xres-add-1, 0); gwy_data_field_invert(dfield, 1, 1, 0); zlfield = gwy_data_field_duplicate(lfield); zdfield = gwy_data_field_duplicate(dfield); /*determine number of spheres necessary for given coverage*/ for (i=0; i<10000; i++) { ax[i] = ay[i] = az[i] = vx[i] = vy[i] = vz[i] = 0; } srand ( time(NULL) ); ndata = 0; /* for test only */ /* disize = mdisize; xpos = oxres/2 - 2*disize; ypos = oyres/2; xdata[ndata] = xpos; ydata[ndata] = ypos; disizes[ndata] = disize; rdisizes[ndata] = size; rx[ndata] = (gdouble)xpos*oxreal/(gdouble)oxres; ry[ndata] = (gdouble)ypos*oyreal/(gdouble)oyres; rz[ndata] = 2.0*gwy_data_field_get_val(lfield, xpos, ypos) + rdisizes[ndata]; ndata++; xpos = oxres/2 + 2*disize; ypos = oyres/2; xdata[ndata] = xpos; ydata[ndata] = ypos; disizes[ndata] = disize; rdisizes[ndata] = size; rx[ndata] = (gdouble)xpos*oxreal/(gdouble)oxres; ry[ndata] = (gdouble)ypos*oyreal/(gdouble)oyres; rz[ndata] = 2.0*gwy_data_field_get_val(lfield, xpos, ypos) + rdisizes[ndata]; ndata++; */ /*end of test*/ i = 0; presetval = args->coverage*10; while (ndata < presetval && i<max) { //disize = mdisize*(0.8+(double)(rand()%20)/40.0); disize = mdisize; xpos = disize+(rand()%(xres-2*(gint)(disize+1))) + 1; ypos = disize+(rand()%(yres-2*(gint)(disize+1))) + 1; i++; { too_close = 0; /*sync real to integer positions*/ for (k=0; k<ndata; k++) { if (((xpos-xdata[k])*(xpos-xdata[k]) + (ypos-ydata[k])*(ypos-ydata[k]))<(4*disize*disize)) { too_close = 1; break; } } if (too_close) continue; if (ndata>=10000) { break; } xdata[ndata] = xpos; ydata[ndata] = ypos; disizes[ndata] = disize; rdisizes[ndata] = size; rx[ndata] = (gdouble)xpos*oxreal/(gdouble)oxres; ry[ndata] = (gdouble)ypos*oyreal/(gdouble)oyres; //printf("surface at %g, particle size %g\n", gwy_data_field_get_val(lfield, xpos, ypos), rdisizes[ndata]); rz[ndata] = 1.0*gwy_data_field_get_val(lfield, xpos, ypos) + rdisizes[ndata]; //2 ndata++; } }; // if (i==max) printf("Maximum reached, only %d particles depositd instead of %d\n", ndata, presetval); // else printf("%d particles depositd\n", ndata); /*refresh shown data and integer positions (necessary in md calculation)*/ gwy_data_field_copy(zlfield, lfield, 0); showit(lfield, zdfield, rdisizes, rx, ry, rz, xdata, ydata, ndata, oxres, oxreal, oyres, oyreal, add, xres, yres); gwy_data_field_area_copy(lfield, dfield, add, add, oxres, oyres, 0, 0); gwy_data_field_data_changed(dfield); for (i=0; i<(20*args->revise); i++) { // printf("###### step %d of %d ##########\n", i, (gint)(20*args->revise)); /*try to add some particles if necessary, do this only for first half of molecular dynamics*/ if (ndata<presetval && i<(10*args->revise)) { ii = 0; nloc = 0; while (ndata < presetval && ii<(max/1000) && nloc<maxloc) { disize = mdisize; xpos = disize+(rand()%(xres-2*(gint)(disize+1))) + 1; ypos = disize+(rand()%(yres-2*(gint)(disize+1))) + 1; ii++; { too_close = 0; rxv = ((gdouble)xpos*oxreal/(gdouble)oxres); ryv = ((gdouble)ypos*oyreal/(gdouble)oyres); rzv = gwy_data_field_get_val(zlfield, xpos, ypos) + 5*size; for (k=0; k<ndata; k++) { if (((rxv-rx[k])*(rxv-rx[k]) + (ryv-ry[k])*(ryv-ry[k]) + (rzv-rz[k])*(rzv-rz[k]))<(4.0*size*size)) { too_close = 1; break; } } if (too_close) continue; if (ndata>=10000) { // printf("Maximum reached!\n"); break; } xdata[ndata] = xpos; ydata[ndata] = ypos; disizes[ndata] = disize; rdisizes[ndata] = size; rx[ndata] = rxv; ry[ndata] = ryv; rz[ndata] = rzv; vz[ndata] = -0.01; ndata++; nloc++; } }; // if (ii==(max/100)) printf("Maximum reached, only %d particles now present instead of %d\n", ndata, presetval); // else printf("%d particles now at surface\n", ndata); } /*test succesive LJ steps on substrate (no relaxation)*/ for (k=0; k<ndata; k++) { fx[k] = fy[k] = fz[k] = 0; /*calculate forces for all particles on substrate*/ if (gwy_data_field_rtoi(lfield, rx[k])<0 || gwy_data_field_rtoj(lfield, ry[k])<0 || gwy_data_field_rtoi(lfield, rx[k])>=xres || gwy_data_field_rtoj(lfield, ry[k])>=yres) continue; for (m=0; m<ndata; m++) { if (m==k) continue; // printf("(%g %g %g) on (%g %g %g)\n", rx[m], ry[m], rz[m], rx[k], ry[k], rz[k]); fx[k] -= (get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k]+diff, ry[k], rz[k], gwy_data_field_itor(dfield, disizes[k])) -get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k]-diff, ry[k], rz[k], gwy_data_field_itor(dfield, disizes[k])))/2/diff; fy[k] -= (get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k], ry[k]+diff, rz[k], gwy_data_field_itor(dfield, disizes[k])) -get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k], ry[k]-diff, rz[k], gwy_data_field_itor(dfield, disizes[k])))/2/diff; fz[k] -= (get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k], ry[k], rz[k]+diff, gwy_data_field_itor(dfield, disizes[k])) -get_lj_potential_spheres(rx[m], ry[m], rz[m], rx[k], ry[k], rz[k]-diff, gwy_data_field_itor(dfield, disizes[k])))/2/diff; } fx[k] -= (integrate_lj_substrate(zlfield, rx[k]+diff, ry[k], rz[k], rdisizes[k]) - integrate_lj_substrate(zlfield, rx[k]-diff, ry[k], rz[k], rdisizes[k]))/2/diff; fy[k] -= (integrate_lj_substrate(zlfield, rx[k], ry[k]-diff, rz[k], rdisizes[k]) - integrate_lj_substrate(zlfield, rx[k], ry[k]+diff, rz[k], rdisizes[k]))/2/diff; fz[k] -= (integrate_lj_substrate(zlfield, rx[k], ry[k], rz[k]+diff, rdisizes[k]) - integrate_lj_substrate(zlfield, rx[k], ry[k], rz[k]-diff, rdisizes[k]))/2/diff; } for (k=0; k<ndata; k++) { if (gwy_data_field_rtoi(lfield, rx[k])<0 || gwy_data_field_rtoj(lfield, ry[k])<0 || gwy_data_field_rtoi(lfield, rx[k])>=xres || gwy_data_field_rtoj(lfield, ry[k])>=yres) continue; /*move all particles*/ rx[k] += vx[k]*timestep + 0.5*ax[k]*timestep*timestep; vx[k] += 0.5*ax[k]*timestep; ax[k] = fx[k]/mass; vx[k] += 0.5*ax[k]*timestep; vx[k] *= 0.9; if (fabs(vx[k])>0.01) vx[k] = 0; //0.2 ry[k] += vy[k]*timestep + 0.5*ay[k]*timestep*timestep; vy[k] += 0.5*ay[k]*timestep; ay[k] = fy[k]/mass; vy[k] += 0.5*ay[k]*timestep; vy[k] *= 0.9; if (fabs(vy[k])>0.01) vy[k] = 0; //0.2 rz[k] += vz[k]*timestep + 0.5*az[k]*timestep*timestep; vz[k] += 0.5*az[k]*timestep; az[k] = fz[k]/mass; vz[k] += 0.5*az[k]*timestep; vz[k] *= 0.9; if (fabs(vz[k])>0.01) vz[k] = 0; if (rx[k]<=gwy_data_field_itor(dfield, disizes[k])) rx[k] = gwy_data_field_itor(dfield, disizes[k]); if (ry[k]<=gwy_data_field_itor(dfield, disizes[k])) ry[k] = gwy_data_field_itor(dfield, disizes[k]); if (rx[k]>=(xreal-gwy_data_field_itor(dfield, disizes[k]))) rx[k] = xreal-gwy_data_field_itor(dfield, disizes[k]); if (ry[k]>=(yreal-gwy_data_field_itor(dfield, disizes[k]))) ry[k] = yreal-gwy_data_field_itor(dfield, disizes[k]); } gwy_data_field_copy(zlfield, lfield, 0); showit(lfield, zdfield, rdisizes, rx, ry, rz, xdata, ydata, ndata, oxres, oxreal, oyres, oyreal, add, xres, yres); gwy_data_field_area_copy(lfield, dfield, add, add, oxres, oyres, 0, 0); gwy_data_field_data_changed(dfield); while (gtk_events_pending()) gtk_main_iteration(); } gwy_data_field_area_copy(lfield, dfield, add, add, oxres, oyres, 0, 0); gwy_data_field_data_changed(dfield); args->computed = TRUE; gwy_object_unref(lfield); gwy_object_unref(zlfield); gwy_object_unref(zdfield); }
static GwyContainer* surffile_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { SurfFile surffile; GwyContainer *meta, *container = NULL; guchar *buffer = NULL; const guchar *p; gsize expected_size, size = 0; GError *err = NULL; gchar signature[12]; gdouble max, min; gint add = 0; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); g_clear_error(&err); return NULL; } if (size < SURF_HEADER_SIZE + 2) { err_TOO_SHORT(error); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } p = buffer; get_CHARARRAY(signature, &p); if (strncmp(signature, "DIGITAL SURF", 12) != 0) { err_FILE_TYPE(error, "Surf"); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } surffile.format = gwy_get_guint16_le(&p); surffile.nobjects = gwy_get_guint16_le(&p); surffile.version = gwy_get_guint16_le(&p); surffile.type = gwy_get_guint16_le(&p); get_CHARS0(surffile.object_name, &p, 30); get_CHARS0(surffile.operator_name, &p, 30); surffile.material_code = gwy_get_guint16_le(&p); surffile.acquisition = gwy_get_guint16_le(&p); surffile.range = gwy_get_guint16_le(&p); surffile.special_points = gwy_get_guint16_le(&p); surffile.absolute = gwy_get_guint16_le(&p); /*reserved*/ p += 8; surffile.pointsize = gwy_get_guint16_le(&p); surffile.zmin = gwy_get_gint32_le(&p); surffile.zmax = gwy_get_gint32_le(&p); surffile.xres = gwy_get_gint32_le(&p); surffile.yres = gwy_get_gint32_le(&p); surffile.nofpoints = gwy_get_guint32_le(&p); surffile.dx = gwy_get_gfloat_le(&p); surffile.dy = gwy_get_gfloat_le(&p); surffile.dz = gwy_get_gfloat_le(&p); get_CHARS0(surffile.xaxis, &p, 16); get_CHARS0(surffile.yaxis, &p, 16); get_CHARS0(surffile.zaxis, &p, 16); get_CHARS0(surffile.dx_unit, &p, 16); get_CHARS0(surffile.dy_unit, &p, 16); get_CHARS0(surffile.dz_unit, &p, 16); get_CHARS0(surffile.xlength_unit, &p, 16); get_CHARS0(surffile.ylength_unit, &p, 16); get_CHARS0(surffile.zlength_unit, &p, 16); surffile.xunit_ratio = gwy_get_gfloat_le(&p); surffile.yunit_ratio = gwy_get_gfloat_le(&p); surffile.zunit_ratio = gwy_get_gfloat_le(&p); surffile.imprint = gwy_get_guint16_le(&p); surffile.inversion = gwy_get_guint16_le(&p); surffile.leveling = gwy_get_guint16_le(&p); p += 12; surffile.seconds = gwy_get_guint16_le(&p); surffile.minutes = gwy_get_guint16_le(&p); surffile.hours = gwy_get_guint16_le(&p); surffile.day = gwy_get_guint16_le(&p); surffile.month = gwy_get_guint16_le(&p); surffile.year = gwy_get_guint16_le(&p); surffile.measurement_duration = gwy_get_guint16_le(&p); surffile.comment_size = gwy_get_guint16_le(&p); surffile.private_size = gwy_get_guint16_le(&p); get_CHARARRAY(surffile.client_zone, &p); surffile.XOffset = gwy_get_gfloat_le(&p); surffile.YOffset = gwy_get_gfloat_le(&p); surffile.ZOffset = gwy_get_gfloat_le(&p); gwy_debug("fileformat: %d, n_of_objects: %d, " "version: %d, object_type: %d", surffile.format, surffile.nobjects, surffile.version, surffile.type); gwy_debug("object name: <%s>", surffile.object_name); gwy_debug("operator name: <%s>", surffile.operator_name); gwy_debug("material code: %d, acquisition type: %d", surffile.material_code, surffile.acquisition); gwy_debug("range type: %d, special points: %d, absolute: %d", surffile.range, surffile.special_points, (gint)surffile.absolute); gwy_debug("data point size: %d", surffile.pointsize); gwy_debug("zmin: %d, zmax: %d", surffile.zmin, surffile.zmax); gwy_debug("xres: %d, yres: %d (xres*yres = %d)", surffile.xres, surffile.yres, (surffile.xres*surffile.yres)); gwy_debug("total number of points: %d", surffile.nofpoints); gwy_debug("dx: %g, dy: %g, dz: %g", surffile.dx, surffile.dy, surffile.dz); gwy_debug("X axis name: %16s", surffile.xaxis); gwy_debug("Y axis name: %16s", surffile.yaxis); gwy_debug("Z axis name: %16s", surffile.zaxis); gwy_debug("dx unit: %16s", surffile.dx_unit); gwy_debug("dy unit: %16s", surffile.dy_unit); gwy_debug("dz unit: %16s", surffile.dz_unit); gwy_debug("X axis unit: %16s", surffile.xlength_unit); gwy_debug("Y axis unit: %16s", surffile.ylength_unit); gwy_debug("Z axis unit: %16s", surffile.zlength_unit); gwy_debug("xunit_ratio: %g, yunit_ratio: %g, zunit_ratio: %g", surffile.xunit_ratio, surffile.yunit_ratio, surffile.zunit_ratio); gwy_debug("imprint: %d, inversion: %d, leveling: %d", surffile.imprint, surffile.inversion, surffile.leveling); gwy_debug("Time: %d:%d:%d, Date: %d.%d.%d", surffile.hours, surffile.minutes, surffile.seconds, surffile.day, surffile.month, surffile.year); gwy_debug("private zone size: %d, comment size %d", surffile.private_size, surffile.comment_size); expected_size = (SURF_HEADER_SIZE + surffile.pointsize/8*surffile.xres*surffile.yres); if (expected_size != size) { gwy_debug("Size mismatch!"); if (size > expected_size) add = size - expected_size; /*TODO correct this !*/ else { err_SIZE_MISMATCH(error, expected_size, size); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } } p = buffer + SURF_HEADER_SIZE + add; if (!fill_data_fields(&surffile, p, error)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } if (!surffile.absolute) { max = gwy_data_field_get_max(surffile.dfield); min = gwy_data_field_get_min(surffile.dfield); gwy_data_field_add(surffile.dfield, -min); gwy_data_field_multiply(surffile.dfield, (surffile.zmax - surffile.zmin)/(max-min)); } switch (surffile.inversion) { case SURF_INV_Z: gwy_data_field_invert(surffile.dfield, FALSE, FALSE, TRUE); break; case SURF_FLIP_Z: gwy_data_field_invert(surffile.dfield, FALSE, TRUE, TRUE); break; case SURF_FLOP_Z: gwy_data_field_invert(surffile.dfield, TRUE, FALSE, TRUE); break; default: break; } container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", surffile.dfield); g_object_unref(surffile.dfield); meta = surffile_get_metadata(&surffile); gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); gwy_app_channel_check_nonsquare(container, 0); return container; }
static GwyContainer* surffile_load(const gchar *filename) { SurfFile surffile; GObject *object = NULL; guchar *buffer = NULL; const guchar *p; gsize size = 0; gsize estsize; GError *err = NULL; gchar signature[12]; gdouble max, min; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { g_warning("Cannot read file %s", filename); g_clear_error(&err); return NULL; } p = buffer; get_CHARARRAY(signature, &p); if (strncmp(signature, "DIGITAL SURF", 12) != 0) { g_warning("File %s is not a Surf file", filename); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } if (size < 500) { g_warning("File %s is too short to be Surf file", filename); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } surffile.format = get_WORD_LE(&p); surffile.nobjects = get_WORD_LE(&p); surffile.version = get_WORD_LE(&p); surffile.type = get_WORD_LE(&p); get_CHARS0(surffile.object_name, &p, 30); get_CHARS0(surffile.operator_name, &p, 30); surffile.material_code = get_WORD_LE(&p); surffile.acquisition = get_WORD_LE(&p); surffile.range = get_WORD_LE(&p); surffile.special_points = get_WORD_LE(&p); surffile.absolute = get_WORD_LE(&p); /*reserved*/ p += 8; surffile.pointsize = get_WORD_LE(&p); surffile.zmin = get_DWORD(&p); surffile.zmax = get_DWORD(&p); surffile.xres = get_DWORD(&p); surffile.yres = get_DWORD(&p); surffile.nofpoints = get_DWORD(&p); //surffile.xres = 200; surffile.yres = 200; surffile.dx = get_FLOAT_LE(&p); surffile.dy = get_FLOAT_LE(&p); surffile.dz = get_FLOAT_LE(&p); get_CHARS0(surffile.xaxis, &p, 16); get_CHARS0(surffile.yaxis, &p, 16); get_CHARS0(surffile.zaxis, &p, 16); get_CHARS0(surffile.dx_unit, &p, 16); get_CHARS0(surffile.dy_unit, &p, 16); get_CHARS0(surffile.dz_unit, &p, 16); get_CHARS0(surffile.xlength_unit, &p, 16); get_CHARS0(surffile.ylength_unit, &p, 16); get_CHARS0(surffile.zlength_unit, &p, 16); surffile.xunit_ratio = get_FLOAT_LE(&p); surffile.yunit_ratio = get_FLOAT_LE(&p); surffile.zunit_ratio = get_FLOAT_LE(&p); surffile.imprint = get_WORD_LE(&p); surffile.inversion = get_WORD_LE(&p); surffile.leveling = get_WORD_LE(&p); p += 12; surffile.seconds = get_WORD_LE(&p); surffile.minutes = get_WORD_LE(&p); surffile.hours = get_WORD_LE(&p); surffile.day = get_WORD_LE(&p); surffile.month = get_WORD_LE(&p); surffile.year = get_WORD_LE(&p); surffile.measurement_duration = get_WORD_LE(&p); surffile.comment_size = get_WORD_LE(&p); surffile.private_size = get_WORD_LE(&p); get_CHARARRAY(surffile.client_zone, &p); surffile.XOffset = get_FLOAT_LE(&p); surffile.YOffset = get_FLOAT_LE(&p); surffile.ZOffset = get_FLOAT_LE(&p); gwy_debug("fileformat: %d, n_of_objects: %d, version: %d, object_type: %d", surffile.format, surffile.nobjects, surffile.version, surffile.type); gwy_debug("object name: %s", surffile.object_name); gwy_debug("operator name: %s", surffile.operator_name); gwy_debug("material code: %d, acquisition type: %d", surffile.material_code, surffile.acquisition); gwy_debug("range type: %d, special points: %d, absolute: %d", surffile.range, surffile.special_points, (gint)surffile.absolute); gwy_debug("data point size: %d", surffile.pointsize); gwy_debug("zmin: %d, zmax: %d", surffile.zmin, surffile.zmax); gwy_debug("xres: %d, yres: %d (xres*yres = %d)", surffile.xres, surffile.yres, (surffile.xres*surffile.yres)); gwy_debug("total number of points: %d", surffile.nofpoints); gwy_debug("dx: %g, dy: %g, dz: %g", surffile.dx, surffile.dy, surffile.dz); gwy_debug("X axis name: %16s", surffile.xaxis); gwy_debug("Y axis name: %16s", surffile.yaxis); gwy_debug("Z axis name: %16s", surffile.zaxis); gwy_debug("dx unit: %16s", surffile.dx_unit); gwy_debug("dy unit: %16s", surffile.dy_unit); gwy_debug("dz unit: %16s", surffile.dz_unit); gwy_debug("X axis unit: %16s", surffile.xlength_unit); gwy_debug("Y axis unit: %16s", surffile.ylength_unit); gwy_debug("Z axis unit: %16s", surffile.zlength_unit); gwy_debug("xunit_ratio: %g, yunit_ratio: %g, zunit_ratio: %g", surffile.xunit_ratio, surffile.yunit_ratio, surffile.zunit_ratio); gwy_debug("imprint: %d, inversion: %d, leveling: %d", surffile.imprint, surffile.inversion, surffile.leveling); gwy_debug("Time: %d:%d:%d, Date: %d.%d.%d", surffile.hours, surffile.minutes, surffile.seconds, surffile.day, surffile.month, surffile.year); p = buffer + 512; estsize = 512 + surffile.pointsize*surffile.xres*surffile.yres/8; if (size < estsize) { g_warning("File %s is too short to contain Surf data %d %d", filename, (int)size, (int)estsize); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } fill_data_fields(&surffile, p); gwy_file_abandon_contents(buffer, size, NULL); if (surffile.absolute == 0) { max = gwy_data_field_get_max(surffile.dfield); min = gwy_data_field_get_min(surffile.dfield); gwy_data_field_add(surffile.dfield, -min); gwy_data_field_multiply(surffile.dfield, (surffile.zmax - surffile.zmin)/(max-min)); } if (surffile.inversion == 1) gwy_data_field_invert(surffile.dfield, FALSE, FALSE, TRUE); if (surffile.inversion == 2) gwy_data_field_invert(surffile.dfield, FALSE, TRUE, TRUE); if (surffile.inversion == 3) gwy_data_field_invert(surffile.dfield, TRUE, FALSE, TRUE); if (surffile.dfield) { object = gwy_container_new(); gwy_container_set_object_by_name(GWY_CONTAINER(object), "/0/data", G_OBJECT(surffile.dfield)); store_metadata(&surffile, GWY_CONTAINER(object)); } return (GwyContainer*)object; return NULL; }
static GwyDataField* read_binary_data(const gchar *buffer, gsize size, GHashTable *hash, GError **error) { ShimadzuDataType data_type; gint xres, yres, i; guint expected; gdouble xreal, yreal, zscale, xoff, yoff, zoff; GwySIUnit *unitxy, *unitz; GwyDataField *dfield = NULL; gdouble *d; const gchar *s; if (!(s = g_hash_table_lookup(hash, "DataType"))) { err_MISSING_FIELD(error, "DataType"); return NULL; } if (g_ascii_strcasecmp(s, "short") == 0) data_type = SHIMADZU_SHORT; else if (g_ascii_strcasecmp(s, "float") == 0) data_type = SHIMADZU_FLOAT; else { err_UNSUPPORTED(error, "DataType"); return NULL; } unitxy = gwy_si_unit_new(NULL); unitz = gwy_si_unit_new(NULL); if (!get_scales(hash, FALSE, &xres, &yres, &xreal, &yreal, &xoff, &yoff, unitxy, &zscale, &zoff, unitz, error)) goto fail; expected = data_type*xres*yres + HEADER_SIZE; if (err_SIZE_MISMATCH(error, expected, size, FALSE)) goto fail; dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); gwy_data_field_set_xoffset(dfield, xoff); gwy_data_field_set_yoffset(dfield, yoff); gwy_data_field_set_si_unit_xy(dfield, unitxy); gwy_data_field_set_si_unit_z(dfield, unitz); d = gwy_data_field_get_data(dfield); if (data_type == SHIMADZU_SHORT) { const gint16 *d16 = (const gint16*)(buffer + HEADER_SIZE); for (i = 0; i < xres*yres; i++) d[i] = zscale*GUINT16_FROM_LE(d16[i]) + zoff; } else if (data_type == SHIMADZU_FLOAT) { const guchar *p = buffer + HEADER_SIZE; for (i = 0; i < xres*yres; i++) d[i] = zscale*gwy_get_gfloat_le(&p) + zoff; } else { g_assert_not_reached(); } gwy_data_field_invert(dfield, TRUE, FALSE, FALSE); fail: g_object_unref(unitxy); g_object_unref(unitz); return dfield; }
static GwyContainer* sly_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL, *meta = NULL; gchar *buffer = NULL; GError *err = NULL; GHashTable *hash = NULL; gchar *p, *line, *value; guint expecting_data = 0; SensolyticsChannel *channels = NULL; Dimensions dimensions; gint ndata = 0, i; if (!g_file_get_contents(filename, &buffer, NULL, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } p = buffer; line = gwy_str_next_line(&p); g_strstrip(line); if (!gwy_strequal(line, MAGIC)) { err_FILE_TYPE(error, "Sensolytics"); goto fail; } hash = g_hash_table_new(g_str_hash, g_str_equal); for (line = gwy_str_next_line(&p); line; line = gwy_str_next_line(&p)) { if (!line[0]) continue; if (expecting_data) { expecting_data--; /* The columns are comma-separated and numbers use decimal points. * Do not tempt the number parsing functions more than necessary * and fix commas to tab characters. */ g_strdelimit(line, ",", '\t'); /* Ignore X, Y and Z, each is two values */ for (i = 0; i < 6; i++) g_ascii_strtod(line, &line); for (i = 0; i < ndata; i++) channels[i].data[expecting_data] = channels[i].q * g_ascii_strtod(line, &line); } else { g_strstrip(line); if (line[0] != '#') { g_warning("Comment line does not start with #."); continue; } do { line++; } while (g_ascii_isspace(*line)); if (g_str_has_prefix(line, "X [")) { if (channels) { g_warning("Multiple data headers!?"); continue; } if (!read_dimensions(hash, &ndata, &dimensions, error) || !(channels = create_fields(hash, line, ndata, &dimensions))) goto fail; expecting_data = dimensions.xres * dimensions.yres; continue; } value = strchr(line, ':'); if (!value) { if (!gwy_strequal(line, "ArrayScan")) g_warning("Non-parameter-like line %s", line); continue; } *value = '\0'; g_strchomp(line); do { value++; } while (g_ascii_isspace(*value)); if (gwy_strequal(line, "Warning")) continue; gwy_debug("<%s>=<%s>", line, value); g_hash_table_insert(hash, line, value); } } if (!channels) { err_NO_DATA(error); goto fail; } container = gwy_container_new(); for (i = 0; i < ndata; i++) { GQuark key = gwy_app_get_data_key_for_id(i); gwy_data_field_invert(channels[i].dfield, FALSE, TRUE, FALSE); gwy_container_set_object(container, key, channels[i].dfield); gwy_app_channel_check_nonsquare(container, i); if (channels[i].name) { gchar *s = g_strconcat(g_quark_to_string(key), "/title", NULL); gwy_container_set_string_by_name(container, s, g_strdup(channels[i].name)); g_free(s); } else gwy_app_channel_title_fall_back(container, i); gwy_file_channel_import_log_add(container, i, NULL, filename); } meta = get_meta(hash); clone_meta(container, meta, ndata); g_object_unref(meta); fail: g_free(buffer); if (hash) g_hash_table_destroy(hash); if (channels) { for (i = 0; i < ndata; i++) g_object_unref(channels[i].dfield); g_free(channels); } return container; }
/** * gwy_tip_cmap: * @tip: Tip data. * @surface: Surface data. * @result: Data field to store ceratainty map data to. * @set_fraction: Function that sets fraction to output (or %NULL). * @set_message: Function that sets message to output (of %NULL). * * Performs certainty map algorithm published by Villarrubia. This function * converts all fields into form requested by "morph_lib.c" library, that is * almost identical with original Villarubia's library. Result certainty map * can be used as a mask of points where tip did not directly touch the * surface. * * Returns: Certainty map, i.e. @result, on success. May return %NULL if * aborted. **/ GwyDataField* gwy_tip_cmap(GwyDataField *tip, GwyDataField *surface, GwyDataField *result, GwySetFractionFunc set_fraction, GwySetMessageFunc set_message) { gint **ftip; gint **fsurface; gint **rsurface; gint **fresult; gint newx, newy; gdouble tipmin, surfacemin, step; GwyDataField *buffertip; gboolean freetip; newx = surface->xres + tip->xres; newy = surface->yres + tip->yres; /*if tip and surface have different spacings, make new, resampled tip*/ buffertip = get_right_tip_field(tip, surface, &freetip); /*invert tip (as necessary by dilation algorithm)*/ gwy_data_field_invert(buffertip, TRUE, TRUE, FALSE); /*convert fields to integer arrays*/ tipmin = gwy_data_field_get_min(buffertip); surfacemin = gwy_data_field_get_min(surface); step = (gwy_data_field_get_max(surface) - surfacemin)/10000; ftip = i_datafield_to_field(buffertip, TRUE, tipmin, step); fsurface = i_datafield_to_largefield(surface, buffertip, surfacemin, step); /*perform erosion as it is necessary parameter of certainty map algorithm*/ rsurface = _gwy_morph_lib_ierosion(fsurface, newy, newx, ftip, buffertip->yres, buffertip->xres, buffertip->yres/2, buffertip->xres/2, set_fraction, set_message); if (!rsurface) { _gwy_morph_lib_ifreematrix(ftip, buffertip->xres); _gwy_morph_lib_ifreematrix(fsurface, newx); if (freetip) g_object_unref(buffertip); return NULL; } /*find certanty map*/ if (rsurface) { fresult = _gwy_morph_lib_icmap(fsurface, newy, newx, ftip, buffertip->yres, buffertip->xres, rsurface, buffertip->yres/2, buffertip->xres/2, set_fraction, set_message); } else fresult = NULL; /*convert result back*/ if (fresult) { gwy_data_field_resample(result, surface->xres, surface->yres, GWY_INTERPOLATION_NONE); result = i_largefield_to_datafield(fresult, result, buffertip, 0.0, 1.0); } else result = NULL; _gwy_morph_lib_ifreematrix(ftip, buffertip->xres); _gwy_morph_lib_ifreematrix(fsurface, newx); _gwy_morph_lib_ifreematrix(rsurface, newx); if (fresult) _gwy_morph_lib_ifreematrix(fresult, result->xres); if (freetip) g_object_unref(buffertip); else gwy_data_field_invert(buffertip, TRUE, TRUE, FALSE); return result; }
static GwyDataField* hash_to_data_field(GHashTable *hash, GHashTable *scannerlist, GHashTable *scanlist, NanoscopeFileType file_type, gboolean has_version, guint bufsize, gchar *buffer, gint gxres, gint gyres, gchar **p, GError **error) { NanoscopeValue *val; GwyDataField *dfield; GwySIUnit *unitz, *unitxy; gchar *s, *end; gchar un[5]; gint xres, yres, bpp, offset, size, power10; gdouble xreal, yreal, q; gdouble *data; gboolean size_ok, use_global; if (!require_keys(hash, error, "Samps/line", "Number of lines", "Scan size", "Data offset", "Data length", NULL)) return NULL; val = g_hash_table_lookup(hash, "Samps/line"); xres = GWY_ROUND(val->hard_value); val = g_hash_table_lookup(hash, "Number of lines"); yres = GWY_ROUND(val->hard_value); val = g_hash_table_lookup(hash, "Bytes/pixel"); bpp = val ? GWY_ROUND(val->hard_value) : 2; /* scan size */ val = g_hash_table_lookup(hash, "Scan size"); xreal = g_ascii_strtod(val->hard_value_str, &end); if (errno || *end != ' ') { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Cannot parse `Scan size' field.")); return NULL; } gwy_debug("xreal = %g", xreal); s = end+1; yreal = g_ascii_strtod(s, &end); if (errno || *end != ' ') { /* Old files don't have two numbers here, assume equal dimensions */ yreal = xreal; end = s; } gwy_debug("yreal = %g", yreal); while (g_ascii_isspace(*end)) end++; if (sscanf(end, "%4s", un) != 1) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Cannot parse `Scan size' field.")); return NULL; } gwy_debug("xy unit: <%s>", un); unitxy = gwy_si_unit_new_parse(un, &power10); q = pow10(power10); xreal *= q; yreal *= q; offset = size = 0; if (file_type == NANOSCOPE_FILE_TYPE_BIN) { val = g_hash_table_lookup(hash, "Data offset"); offset = GWY_ROUND(val->hard_value); val = g_hash_table_lookup(hash, "Data length"); size = GWY_ROUND(val->hard_value); size_ok = FALSE; use_global = FALSE; /* Try channel size and local size */ if (!size_ok && size == bpp*xres*yres) size_ok = TRUE; if (!size_ok && size == bpp*gxres*gyres) { size_ok = TRUE; use_global = TRUE; } /* If they don't match exactly, try whether they at least fit inside */ if (!size_ok && size > bpp*MAX(xres*yres, gxres*gyres)) { size_ok = TRUE; use_global = (xres*yres < gxres*gyres); } if (!size_ok && size > bpp*MIN(xres*yres, gxres*gyres)) { size_ok = TRUE; use_global = (xres*yres > gxres*gyres); } if (!size_ok) { err_SIZE_MISMATCH(error, size, bpp*xres*yres); return NULL; } if (use_global) { if (gxres) { xreal *= (gdouble)gxres/xres; xres = gxres; } if (gyres) { yreal *= (gdouble)gyres/yres; yres = gyres; } } if (offset + size > (gint)bufsize) { err_SIZE_MISMATCH(error, offset + size, bufsize); return NULL; } } q = 1.0; unitz = get_physical_scale(hash, scannerlist, scanlist, has_version, &q, error); if (!unitz) return NULL; dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); data = gwy_data_field_get_data(dfield); switch (file_type) { case NANOSCOPE_FILE_TYPE_TXT: if (!read_ascii_data(xres*yres, data, p, bpp, error)) { g_object_unref(dfield); return NULL; } break; case NANOSCOPE_FILE_TYPE_BIN: if (!read_binary_data(xres*yres, data, buffer + offset, bpp, error)) { g_object_unref(dfield); return NULL; } break; default: g_assert_not_reached(); break; } gwy_data_field_multiply(dfield, q); gwy_data_field_invert(dfield, TRUE, FALSE, FALSE); gwy_data_field_set_si_unit_z(dfield, unitz); g_object_unref(unitz); gwy_data_field_set_si_unit_xy(dfield, unitxy); g_object_unref(unitxy); return dfield; }
static GwyDataField* igor_read_data_field(const IgorFile *igorfile, const guchar *buffer, guint i, const gchar *zunits, gboolean imaginary) { const IgorWaveHeader5 *wave5; guint n, xres, yres, skip; GwyDataField *dfield; GwySIUnit *unit; gdouble *data; const guchar *p; gint power10; gdouble q; wave5 = &igorfile->wave5; xres = wave5->n_dim[0]; yres = wave5->n_dim[1]; p = buffer + igorfile->headers_size + xres*yres*igorfile->type_size*i; n = xres*yres; dfield = gwy_data_field_new(xres, yres, wave5->sfA[0]*xres, wave5->sfA[1]*yres, FALSE); data = gwy_data_field_get_data(dfield); g_return_val_if_fail(!imaginary || (wave5->type & IGOR_COMPLEX), dfield); skip = imaginary ? igorfile->type_size/2 : 0; if (imaginary) p += skip; /* TODO: Support extended units */ unit = gwy_data_field_get_si_unit_xy(dfield); gwy_si_unit_set_from_string_parse(unit, wave5->dim_units[0], &power10); gwy_data_field_set_xreal(dfield, pow10(power10)*wave5->sfA[0]*xres); gwy_data_field_set_yreal(dfield, pow10(power10)*wave5->sfA[1]*yres); unit = gwy_data_field_get_si_unit_z(dfield); gwy_si_unit_set_from_string_parse(unit, zunits ? zunits : wave5->data_units, &power10); q = pow10(power10); switch ((guint)wave5->type) { case IGOR_INT8: { const gint8 *ps = (const gint8*)buffer; while (n--) { *(data++) = *(ps++) * q; ps += skip; } } break; case IGOR_INT8 | IGOR_UNSIGNED: while (n--) { *(data++) = *(p++) * q; p += skip; } break; case IGOR_INT16: while (n--) { *(data++) = igorfile->get_gint16(&p) * q; p += skip; } break; case IGOR_INT16 | IGOR_UNSIGNED: while (n--) { *(data++) = igorfile->get_guint16(&p) * q; p += skip; } break; case IGOR_INT32: while (n--) { *(data++) = igorfile->get_gint32(&p) * q; p += skip; } break; case IGOR_INT32 | IGOR_UNSIGNED: while (n--) { *(data++) = igorfile->get_guint32(&p) * q; p += skip; } break; case IGOR_SINGLE: while (n--) { *(data++) = igorfile->get_gfloat(&p) * q; p += skip; } break; case IGOR_DOUBLE: while (n--) { *(data++) = igorfile->get_gdouble(&p) * q; p += skip; } break; default: g_return_val_if_reached(NULL); break; } gwy_data_field_invert(dfield, TRUE, FALSE, FALSE); return dfield; }
static void level_grains_do(const LevelGrainsArgs *args, GwyContainer *data, GQuark dquark, gint id, GwyDataField *dfield, GwyDataField *mfield) { GwyDataField *buffer, *background, *invmask; gdouble error, cor, maxerr, lastfrac, frac, starterr; gdouble *heights, *bgdata; gint *grains; gboolean cancelled = FALSE; gint i, xres, yres, ngrains; xres = gwy_data_field_get_xres(mfield); yres = gwy_data_field_get_yres(mfield); grains = g_new0(gint, xres*yres); ngrains = gwy_data_field_number_grains(mfield, grains); if (!ngrains) { g_free(grains); return; } heights = g_new(gdouble, ngrains+1); gwy_data_field_grains_get_values(dfield, heights, ngrains, grains, args->base); heights[0] = 0.0; background = gwy_data_field_new_alike(dfield, FALSE); bgdata = gwy_data_field_get_data(background); for (i = 0; i < xres*yres; i++) bgdata[i] = -heights[grains[i]]; invmask = gwy_data_field_duplicate(mfield); gwy_data_field_multiply(invmask, -1.0); gwy_data_field_add(invmask, 1.0); maxerr = gwy_data_field_get_rms(dfield)/1.0e4; gwy_app_wait_start(gwy_app_find_window_for_channel(data, id), _("Laplace interpolation...")); g_free(heights); g_free(grains); buffer = gwy_data_field_new_alike(background, TRUE); gwy_data_field_correct_average(background, invmask); cor = 0.2; error = 0.0; lastfrac = 0.0; starterr = 0.0; for (i = 0; i < 5000; i++) { gwy_data_field_correct_laplace_iteration(background, invmask, buffer, cor, &error); if (error < maxerr) break; if (!i) starterr = error; frac = log(error/starterr)/log(maxerr/starterr); if ((i/(gdouble)(5000)) > frac) frac = i/(gdouble)(5000); if (lastfrac > frac) frac = lastfrac; if (!gwy_app_wait_set_fraction(frac)) { cancelled = TRUE; break; } lastfrac = frac; } gwy_app_wait_finish(); if (!cancelled) { gwy_data_field_invert(background, FALSE, FALSE, TRUE); gwy_app_undo_qcheckpointv(data, 1, &dquark); gwy_data_field_subtract_fields(dfield, dfield, background); gwy_data_field_data_changed(dfield); if (args->do_extract) { gint newid; newid = gwy_app_data_browser_add_data_field(background, data, TRUE); gwy_app_sync_data_items(data, data, id, newid, FALSE, GWY_DATA_ITEM_GRADIENT, 0); gwy_app_set_data_field_title(data, newid, _("Background")); } } g_object_unref(buffer); g_object_unref(invmask); g_object_unref(background); }
static GwyContainer* fits_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL; fitsfile *fptr = NULL; GwyDataField *field = NULL, *mask; gint status = 0; /* Must be initialised to zero! */ gint hdutype, naxis, anynull, nkeys, k; glong res[3]; /* First index is the fast looping one. */ char strvalue[FLEN_VALUE]; gchar *invalid = NULL; gdouble real, off; if (fits_open_image(&fptr, filename, READONLY, &status)) { err_FITS(error, status); return NULL; } if (fits_get_hdu_type(fptr, &hdutype, &status)) { err_FITS(error, status); goto fail; } gwy_debug("hdutype %d", hdutype); if (hdutype != IMAGE_HDU) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only two-dimensional images are supported.")); goto fail; } if (fits_get_img_dim(fptr, &naxis, &status)) { err_FITS(error, status); goto fail; } gwy_debug("naxis %d", naxis); if (naxis != 2 && naxis != 3) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only two-dimensional images are supported.")); goto fail; } if (fits_get_img_size(fptr, naxis, res, &status)) { err_FITS(error, status); goto fail; } if (naxis == 3 && res[2] != 1) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only two-dimensional images are supported.")); goto fail; } gwy_debug("xres %ld, yres %ld", res[0], res[1]); if (err_DIMENSION(error, res[0]) || err_DIMENSION(error, res[1])) goto fail; field = gwy_data_field_new(res[0], res[1], res[0], res[1], FALSE); invalid = g_new(gchar, res[0]*res[1]); if (fits_read_imgnull(fptr, TDOUBLE, 1, res[0]*res[1], field->data, invalid, &anynull, &status)) { err_FITS(error, status); goto fail; } container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", field); /* Failures here are non-fatal. We already have an image. */ if (fits_get_hdrspace(fptr, &nkeys, NULL, &status)) { g_warning("Cannot get the first hdrspace."); goto fail; } if (!fits_read_key(fptr, TSTRING, "BUINT ", strvalue, NULL, &status)) { gint power10; gwy_debug("BUINT = <%s>", strvalue); gwy_si_unit_set_from_string_parse(gwy_data_field_get_si_unit_z(field), strvalue, &power10); if (power10) gwy_data_field_multiply(field, pow10(power10)); } status = 0; if (get_real_and_offset(fptr, 1, res[0], &real, &off)) { if (real < 0.0) { off += real; real = -real; gwy_data_field_invert(field, FALSE, TRUE, FALSE); } gwy_data_field_set_xreal(field, real); gwy_data_field_set_xoffset(field, off); } if (get_real_and_offset(fptr, 2, res[1], &real, &off)) { if (real < 0.0) { off += real; real = -real; gwy_data_field_invert(field, TRUE, FALSE, FALSE); } gwy_data_field_set_yreal(field, real); gwy_data_field_set_yoffset(field, off); } /* Create a mask of invalid data. */ for (k = 0; k < field->xres*field->yres; k++) { if (invalid[k]) field->data[k] = NAN; } if ((mask = gwy_app_channel_mask_of_nans(field, TRUE))) { gwy_container_set_object_by_name(container, "/0/mask", mask); g_object_unref(mask); } fail: fits_close_file(fptr, &status); gwy_object_unref(field); g_free(invalid); return container; }