static void gwy_hmarker_box_draw_marker(GwyMarkerBox *mbox, gint i) { GtkWidget *widget; GtkStateType state, gcstate; gboolean ghost, selected; GdkPoint points[3]; gint height, width; gdouble pos; gint iw, ipos; widget = GTK_WIDGET(mbox); state = GTK_WIDGET_STATE(widget); width = widget->allocation.width; height = widget->allocation.height; selected = (i == mbox->selected); ghost = selected && mbox->ghost; selected = selected && mbox->highlight; pos = g_array_index(mbox->markers, gdouble, i); if (ghost) gcstate = GTK_STATE_INSENSITIVE; else if (state == GTK_STATE_INSENSITIVE) gcstate = state; else gcstate = GTK_STATE_NORMAL; ipos = GWY_ROUND(pos*(width - 1)); iw = MAX(GWY_ROUND(height/GWY_SQRT3 - 1), 1); points[0].x = ipos - iw; points[1].x = ipos + iw; points[2].x = ipos; if (mbox->flipped) { points[0].y = 0; points[1].y = 0; points[2].y = height-1; } else { points[0].y = height-1; points[1].y = height-1; points[2].y = 0; } if (selected && !ghost) gdk_draw_polygon(widget->window, widget->style->bg_gc[GTK_STATE_SELECTED], TRUE, points, G_N_ELEMENTS(points)); else gdk_draw_polygon(widget->window, widget->style->text_gc[gcstate], TRUE, points, G_N_ELEMENTS(points)); gdk_draw_polygon(widget->window, widget->style->fg_gc[gcstate], FALSE, points, G_N_ELEMENTS(points)); }
static void get_scan_list_res(GHashTable *hash, gint *xres, gint *yres) { NanoscopeValue *val; /* XXX: Some observed files contained correct dimensions only in * a global section, sizes in `image list' sections were bogus. * Version: 0x05300001 */ if ((val = g_hash_table_lookup(hash, "Samps/line"))) *xres = GWY_ROUND(val->hard_value); if ((val = g_hash_table_lookup(hash, "Lines"))) *yres = GWY_ROUND(val->hard_value); gwy_debug("Global xres, yres = %d, %d", *xres, *yres); }
static GwyDataLine* sphrev_make_sphere(gdouble radius, gint maxres) { GwyDataLine *dline; gdouble *data; gint i, size; size = GWY_ROUND(MIN(radius, maxres)); dline = gwy_data_line_new(2*size+1, 1.0, FALSE); data = gwy_data_line_get_data(dline); if (radius/8 > maxres) { /* Pathological case: very flat sphere */ for (i = 0; i <= size; i++) { gdouble u = i/radius; data[size+i] = data[size-i] = u*u/2.0*(1.0 + u*u/4.0*(1 + u*u/2.0)); } } else { /* Normal sphere */ for (i = 0; i <= size; i++) { gdouble u = i/radius; if (G_UNLIKELY(u > 1.0)) data[size+i] = data[size-i] = 1.0; else data[size+i] = data[size-i] = 1.0 - sqrt(1.0 - u*u); } } return dline; }
static gint burleigh_detect(const GwyFileDetectInfo *fileinfo, gboolean only_name) { const guchar *buffer; guint version_int, xres, yres; gdouble version; if (only_name) return g_str_has_suffix(fileinfo->name_lowercase, EXTENSION) ? 10 : 0; if (fileinfo->buffer_len < 4) return 0; buffer = fileinfo->head; version = gwy_get_gfloat_le(&buffer); version_int = GWY_ROUND(10*version); gwy_debug("Version: %g", version); if (version_int == 21) { if (fileinfo->file_size < TOTAL_SIZE_V21 + 2) return 0; xres = gwy_get_guint16_le(&buffer); yres = gwy_get_guint16_le(&buffer); if (fileinfo->file_size == TOTAL_SIZE_V21 + 2*xres*yres) return 100; return 0; } return 0; }
static void prof_update_curve(ProfControls *controls, gint i) { GwyGraphCurveModel *gcmodel; gdouble xy[4], h; gint xl0, yl0, xl1, yl1; gint n, lineres; gchar *desc; g_return_if_fail(gwy_selection_get_object(controls->selection, i, xy)); /* The ω=0 pixel is always at res/2, for even dimensions it means it is * shifted half-a-pixel to the right from the precise centre. */ xl0 = gwy_data_field_get_xres(controls->psdffield)/2; yl0 = gwy_data_field_get_yres(controls->psdffield)/2; xl1 = floor(gwy_data_field_rtoj(controls->psdffield, xy[0])); yl1 = floor(gwy_data_field_rtoi(controls->psdffield, xy[1])); xy[0] += gwy_data_field_get_xoffset(controls->psdffield); xy[1] += gwy_data_field_get_yoffset(controls->psdffield); h = hypot(controls->hx*xy[0], controls->hy*xy[1])/hypot(xy[0], xy[1]); if (!controls->args->fixres) { lineres = GWY_ROUND(hypot(abs(xl0 - xl1) + 1, abs(yl0 - yl1) + 1)); lineres = MAX(lineres, MIN_RESOLUTION); } else lineres = controls->args->resolution; gwy_data_field_get_profile(controls->psdffield, controls->line, xl0, yl0, xl1, yl1, lineres, 1, controls->args->interpolation); gwy_data_line_multiply(controls->line, h); n = gwy_graph_model_get_n_curves(controls->gmodel); if (i < n) { gcmodel = gwy_graph_model_get_curve(controls->gmodel, i); } else { gcmodel = gwy_graph_curve_model_new(); g_object_set(gcmodel, "mode", GWY_GRAPH_CURVE_LINE, "color", gwy_graph_get_preset_color(i), NULL); gwy_graph_model_add_curve(controls->gmodel, gcmodel); g_object_unref(gcmodel); } gwy_graph_curve_model_set_data_from_dataline(gcmodel, controls->line, 0, 0); desc = g_strdup_printf(_("PSDF %.0f°"), 180.0/G_PI*atan2(-xy[1], xy[0])); g_object_set(gcmodel, "description", desc, NULL); g_free(desc); }
static gint gwy_hmarker_box_find_nearest(GwyMarkerBox *mbox, gint x, gint y) { GtkWidget *widget; gint ii, mdist, width, height, ipos; gdouble pos; guint i; widget = GTK_WIDGET(mbox); width = widget->allocation.width; height = widget->allocation.height; ii = -1; mdist = G_MAXINT; for (i = 0; i < mbox->markers->len; i++) { pos = g_array_index(mbox->markers, gdouble, i); ipos = GWY_ROUND(pos*(width - 1)); if (ipos == x) return i; if (ABS(ipos - x) < mdist) { mdist = ABS(ipos - x); ii = i; } else if (ipos > x) break; } if (ii < 0) return -1; pos = g_array_index(mbox->markers, gdouble, ii); ipos = GWY_ROUND(pos*(width - 1)); if (mbox->flipped) y = height-1 - y; return ABS(ipos - x) <= y/GWY_SQRT3 ? ii : -1; }
static void poly_level_degree_changed(GtkObject *spin, PolyLevelControls *controls) { PolyLevelArgs *args; gdouble v; gint degree; gboolean update; if (controls->in_update) return; args = controls->args; v = gtk_adjustment_get_value(GTK_ADJUSTMENT(spin)); degree = GWY_ROUND(v); if (spin == controls->col_degree) { update = args->col_degree != degree; args->col_degree = degree; } else { update = args->row_degree != degree; args->row_degree = degree; } if (!args->same_degree) { poly_level_update_preview(controls, controls->args); return; } controls->in_update = TRUE; if (spin == controls->col_degree) { gwy_debug("syncing row := col"); gtk_adjustment_set_value(GTK_ADJUSTMENT(controls->row_degree), v); args->row_degree = args->col_degree; } else { gwy_debug("syncing col := row"); gtk_adjustment_set_value(GTK_ADJUSTMENT(controls->col_degree), v); args->col_degree = args->row_degree; } gwy_debug("col_degree = %f %d, row_degree = %f %d", gtk_adjustment_get_value(GTK_ADJUSTMENT(controls->col_degree)), args->col_degree, gtk_adjustment_get_value(GTK_ADJUSTMENT(controls->row_degree)), args->row_degree); if (update) poly_level_update_preview(controls, controls->args); controls->in_update = FALSE; }
static gboolean gwy_hmarker_box_button_press(GtkWidget *widget, GdkEventButton *event) { GwyMarkerBox *mbox; gint x, y, i, ipos, width; gdouble pos; /* React to left button only */ mbox = GWY_MARKER_BOX(widget); if (event->button != 1) return FALSE; x = (gint)event->x; y = (gint)event->y; width = widget->allocation.width; i = gwy_hmarker_box_find_nearest(mbox, x, y); if (i < 0) { /* Control enforces selection, no markers are added */ if ((event->state & GDK_CONTROL_MASK)) return FALSE; pos = (x - mbox->offset)/(widget->allocation.width - 1.0); i = gwy_marker_box_add_marker(mbox, mbox->markers->len, pos); if (i < 0) return FALSE; } /* Control deselect a selected marker */ if ((event->state & GDK_CONTROL_MASK) && i == mbox->selected) { gwy_marker_box_set_selected_marker(mbox, -1); return FALSE; } pos = g_array_index(mbox->markers, gdouble, i); ipos = GWY_ROUND(pos*(width - 1)); mbox->button = event->button; mbox->offset = x - ipos; mbox->moved = FALSE; gwy_marker_box_set_selected_marker(mbox, i); return FALSE; }
static void poly_level_max_degree_changed(GtkObject *spin, PolyLevelControls *controls) { PolyLevelArgs *args; gdouble v; gint degree; if (controls->in_update) return; args = controls->args; v = gtk_adjustment_get_value(GTK_ADJUSTMENT(spin)); degree = GWY_ROUND(v); if (degree == args->max_degree) return; args->max_degree = degree; poly_level_update_preview(controls, controls->args); }
static gint* median_make_circle(gint radius) { gint *data; gint i; data = g_new(gint, 2*radius + 1); for (i = 0; i <= radius; i++) { gdouble u = (gdouble)i/radius; if (G_UNLIKELY(u > 1.0)) data[radius+i] = data[radius-i] = 0; else data[radius+i] = data[radius-i] = GWY_ROUND(radius*sqrt(1.0 - u*u)); } return data; }
static void height_changed(GtkAdjustment *adj, TipBlindControls *controls) { TipBlindArgs *args; gdouble v; args = controls->args; v = gtk_adjustment_get_value(adj); args->yres = GWY_ROUND(v); if (controls->in_update) return; if (args->same_resolution) { controls->in_update = TRUE; gtk_adjustment_set_value(GTK_ADJUSTMENT(controls->xres), v); controls->in_update = FALSE; } tip_update(controls); }
static void median(GwyContainer *data, GwyRunType run) { GwyDataField *dfield, *background = NULL; MedianBgArgs args; gint oldid, newid; GQuark dquark; gdouble xr, yr; gboolean ok = TRUE; g_return_if_fail(run & MEDIANBG_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield, GWY_APP_DATA_FIELD_KEY, &dquark, GWY_APP_DATA_FIELD_ID, &oldid, 0); g_return_if_fail(dfield && dquark); median_load_args(gwy_app_settings_get(), &args); /* FIXME: this is bogus for non-square pixels anyway */ xr = gwy_data_field_get_xreal(dfield)/gwy_data_field_get_xres(dfield); yr = gwy_data_field_get_yreal(dfield)/gwy_data_field_get_yres(dfield); args.pixelsize = hypot(xr, yr); args.valform = gwy_data_field_get_value_format_xy(dfield, GWY_SI_UNIT_FORMAT_VFMARKUP, NULL); gwy_debug("pixelsize = %g, vf = (%g, %d, %s)", args.pixelsize, args.valform->magnitude, args.valform->precision, args.valform->units); if (run == GWY_RUN_INTERACTIVE) { ok = median_dialog(&args); median_save_args(gwy_app_settings_get(), &args); } gwy_si_unit_value_format_free(args.valform); if (!ok) return; gwy_app_wait_start(gwy_app_find_window_for_channel(data, oldid), _("Median-leveling...")); background = median_background(GWY_ROUND(args.size), dfield); gwy_app_wait_finish(); if (!background) return; gwy_app_undo_qcheckpointv(data, 1, &dquark); gwy_data_field_subtract_fields(dfield, dfield, background); gwy_data_field_data_changed(dfield); gwy_app_channel_log_add_proc(data, oldid, oldid); if (!args.do_extract) { g_object_unref(background); return; } newid = gwy_app_data_browser_add_data_field(background, data, TRUE); g_object_unref(background); gwy_app_sync_data_items(data, data, oldid, newid, FALSE, GWY_DATA_ITEM_GRADIENT, 0); gwy_app_set_data_field_title(data, newid, _("Background")); gwy_app_channel_log_add(data, oldid, newid, NULL, NULL); }
static void immerse_do(ImmerseArgs *args) { GwyDataField *resampled, *image, *detail, *result; GwyContainer *data; gint newid; gint kxres, kyres; gint x, y, w, h; gdouble iavg, davg; GQuark quark; data = gwy_app_data_browser_get(args->image.datano); quark = gwy_app_get_data_key_for_id(args->image.id); image = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); data = gwy_app_data_browser_get(args->detail.datano); quark = gwy_app_get_data_key_for_id(args->detail.id); detail = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); davg = gwy_data_field_get_avg(detail); kxres = gwy_data_field_get_xres(detail); kyres = gwy_data_field_get_yres(detail); switch (args->sampling) { case GWY_IMMERSE_SAMPLING_DOWN: result = gwy_data_field_duplicate(image); x = gwy_data_field_rtoj(image, args->xpos); y = gwy_data_field_rtoi(image, args->ypos); w = GWY_ROUND(gwy_data_field_get_xreal(detail) /gwy_data_field_get_xmeasure(image)); h = GWY_ROUND(gwy_data_field_get_yreal(detail) /gwy_data_field_get_ymeasure(image)); w = MAX(w, 1); h = MAX(h, 1); gwy_debug("w: %d, h: %d", w, h); resampled = gwy_data_field_new_resampled(detail, w, h, GWY_INTERPOLATION_LINEAR); if (args->leveling == GWY_IMMERSE_LEVEL_MEAN) { iavg = gwy_data_field_area_get_avg(result, NULL, x, y, w, h); gwy_data_field_add(resampled, iavg - davg); } gwy_data_field_area_copy(resampled, result, 0, 0, w, h, x, y); g_object_unref(resampled); break; case GWY_IMMERSE_SAMPLING_UP: w = GWY_ROUND(gwy_data_field_get_xreal(image) /gwy_data_field_get_xmeasure(detail)); h = GWY_ROUND(gwy_data_field_get_yreal(image) /gwy_data_field_get_ymeasure(detail)); gwy_debug("w: %d, h: %d", w, h); result = gwy_data_field_new_resampled(image, w, h, GWY_INTERPOLATION_LINEAR); x = gwy_data_field_rtoj(result, args->xpos); y = gwy_data_field_rtoi(result, args->ypos); if (args->leveling == GWY_IMMERSE_LEVEL_MEAN) { iavg = gwy_data_field_area_get_avg(result, NULL, x, y, kxres, kyres); gwy_data_field_area_copy(detail, result, 0, 0, kxres, kyres, x, y); gwy_data_field_area_add(result, x, y, kxres, kyres, iavg - davg); } else gwy_data_field_area_copy(detail, result, 0, 0, kxres, kyres, x, y); break; default: g_return_if_reached(); break; } gwy_app_data_browser_get_current(GWY_APP_CONTAINER, &data, 0); newid = gwy_app_data_browser_add_data_field(result, data, TRUE); gwy_app_set_data_field_title(data, newid, _("Immersed detail")); g_object_unref(result); gwy_app_channel_log_add_proc(data, args->image.id, newid); }
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 void immerse_correlate(GwyDataField *image, GwyDataField *kernel, gint *col, gint *row) { GwyDataField *subimage, *subkernel, *score, *imagearea; gdouble factor; gint ixres, iyres, kxres, kyres; gint sixres, siyres, skxres, skyres; gint xfrom, yfrom, xto, yto; gint sx, sy, delta; ixres = gwy_data_field_get_xres(image); iyres = gwy_data_field_get_yres(image); kxres = gwy_data_field_get_xres(kernel); kyres = gwy_data_field_get_yres(kernel); gwy_debug("kernel: %dx%d, image: %dx%d", kxres, kyres, ixres, iyres); factor = MAX(downsample_factor, downsample_limit/sqrt(kxres*kyres)); factor = MIN(factor, 1.0); skxres = GWY_ROUND(factor*kxres); skyres = GWY_ROUND(factor*kyres); sixres = GWY_ROUND(factor*ixres); siyres = GWY_ROUND(factor*iyres); gwy_debug("skernel: %dx%d, simage: %dx%d", skxres, skyres, sixres, siyres); subimage = gwy_data_field_new_resampled(image, sixres, siyres, GWY_INTERPOLATION_LINEAR); score = gwy_data_field_new_alike(subimage, FALSE); subkernel = gwy_data_field_new_resampled(kernel, skxres, skyres, GWY_INTERPOLATION_LINEAR); gwy_data_field_correlate(subimage, subkernel, score, GWY_CORRELATION_NORMAL); immerse_find_maximum(score, &sx, &sy); gwy_debug("sx: %d, sy: %d", sx, sy); g_object_unref(score); g_object_unref(subkernel); g_object_unref(subimage); /* Top left corner coordinate */ sx -= (skxres - 1)/2; sy -= (skyres - 1)/2; /* Upscaled to original size */ sx = GWY_ROUND((gdouble)ixres/sixres*sx); sy = GWY_ROUND((gdouble)iyres/siyres*sy); /* Uncertainty margin */ delta = GWY_ROUND(1.5/factor + 1); /* Subarea to search */ xfrom = MAX(sx - delta, 0); yfrom = MAX(sy - delta, 0); xto = MIN(sx + kxres + delta, ixres); yto = MIN(sy + kyres + delta, iyres); imagearea = gwy_data_field_area_extract(image, xfrom, yfrom, xto - xfrom, yto - yfrom); score = gwy_data_field_new_alike(imagearea, FALSE); gwy_data_field_correlate(imagearea, kernel, score, GWY_CORRELATION_NORMAL); immerse_find_maximum(score, &sx, &sy); g_object_unref(score); g_object_unref(imagearea); *col = sx + xfrom - (kxres - 1)/2; *row = sy + yfrom - (kyres - 1)/2; }
static void immerse_search(ImmerseControls *controls, gint search_type) { GwyDataField *dfield, *dfieldsub, *ifield, *iarea; gdouble wr, hr, xpos, ypos, deltax, deltay; gint w, h, xfrom, xto, yfrom, yto, ixres, iyres, col, row; GwyContainer *data; GQuark quark; data = gwy_app_data_browser_get(controls->args->detail.datano); quark = gwy_app_get_data_key_for_id(controls->args->detail.id); dfield = gwy_container_get_object(data, quark); data = gwy_app_data_browser_get(controls->args->image.datano); quark = gwy_app_get_data_key_for_id(controls->args->image.id); ifield = gwy_container_get_object(data, quark); ixres = gwy_data_field_get_xres(ifield); iyres = gwy_data_field_get_yres(ifield); wr = gwy_data_field_get_xreal(dfield)/gwy_data_field_get_xmeasure(ifield); hr = gwy_data_field_get_yreal(dfield)/gwy_data_field_get_ymeasure(ifield); if (wr*hr < 6.0) { g_warning("Detail image is too small for correlation"); return; } w = GWY_ROUND(MAX(wr, 1.0)); h = GWY_ROUND(MAX(hr, 1.0)); gwy_debug("w: %d, h: %d", w, h); g_assert(w <= ixres && h <= iyres); if (search_type == RESPONSE_REFINE) { xfrom = gwy_data_field_rtoj(ifield, controls->args->xpos); yfrom = gwy_data_field_rtoi(ifield, controls->args->ypos); /* Calculate the area we will search the detail in */ deltax = improve_search_window(w, ixres); deltay = improve_search_window(h, iyres); gwy_debug("deltax: %g, deltay: %g", deltax, deltay); xto = MIN(xfrom + w + deltax, ixres); yto = MIN(yfrom + h + deltay, iyres); xfrom = MAX(xfrom - deltax, 0); yfrom = MAX(yfrom - deltay, 0); } else { xfrom = yfrom = 0; xto = ixres; yto = iyres; } gwy_debug("x: %d..%d, y: %d..%d", xfrom, xto, yfrom, yto); /* Cut out only the interesting part from the image data field */ if (xfrom == 0 && yfrom == 0 && xto == ixres && yto == iyres) iarea = g_object_ref(ifield); else iarea = gwy_data_field_area_extract(ifield, xfrom, yfrom, xto - xfrom, yto - yfrom); dfieldsub = gwy_data_field_new_resampled(dfield, w, h, GWY_INTERPOLATION_LINEAR); immerse_correlate(iarea, dfieldsub, &col, &row); gwy_debug("[c] col: %d, row: %d", col, row); col += xfrom; row += yfrom; xpos = gwy_data_field_jtor(dfieldsub, col + 0.5); ypos = gwy_data_field_itor(dfieldsub, row + 0.5); g_object_unref(iarea); g_object_unref(dfieldsub); gwy_debug("[C] col: %d, row: %d", col, row); /* Upsample and refine */ xfrom = MAX(col - 1, 0); yfrom = MAX(row - 1, 0); xto = MIN(col + w + 1, ixres); yto = MIN(row + h + 1, iyres); gwy_debug("x: %d..%d, y: %d..%d", xfrom, xto, yfrom, yto); iarea = gwy_data_field_area_extract(ifield, xfrom, yfrom, xto - xfrom, yto - yfrom); wr = gwy_data_field_get_xreal(iarea)/gwy_data_field_get_xmeasure(dfield); hr = gwy_data_field_get_yreal(iarea)/gwy_data_field_get_ymeasure(dfield); gwy_data_field_resample(iarea, GWY_ROUND(wr), GWY_ROUND(hr), GWY_INTERPOLATION_LINEAR); immerse_correlate(iarea, dfield, &col, &row); gwy_debug("[U] col: %d, row: %d", col, row); xpos = gwy_data_field_jtor(dfield, col + 0.5) + gwy_data_field_jtor(ifield, xfrom); ypos = gwy_data_field_itor(dfield, row + 0.5) + gwy_data_field_itor(ifield, yfrom); g_object_unref(iarea); immerse_clamp_detail_offset(controls, xpos, ypos); }
static GwyContainer* burleigh_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwySIUnit *unit; GwyContainer *container = NULL; guchar *buffer = NULL; const guchar *p; gsize size = 0; GError *err = NULL; IMGFile imgfile; GwyDataField *dfield; gdouble *data; const gint16 *d; gdouble zoom; guint i; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < HEADER_SIZE_MIN + 2) { err_TOO_SHORT(error); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } gwy_clear(&imgfile, 1); p = buffer; imgfile.version = gwy_get_gfloat_le(&p); imgfile.version_int = GWY_ROUND(10*imgfile.version); if (imgfile.version_int == 21) { d = burleigh_load_v21(&imgfile, buffer, size, error); if (!d) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } } else { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("File format version %.1f is not supported."), imgfile.version); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } zoom = burleigh_get_zoom_v21(&imgfile); if (err_DIMENSION(error, imgfile.xres) || err_DIMENSION(error, imgfile.yres)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } dfield = gwy_data_field_new(imgfile.xres, imgfile.yres, Angstrom*imgfile.xrange/zoom, Angstrom*imgfile.yrange/zoom, FALSE); data = gwy_data_field_get_data(dfield); for (i = 0; i < imgfile.xres*imgfile.yres; i++) data[i] = GINT16_FROM_LE(d[i])*imgfile.zrange/4095.0; gwy_file_abandon_contents(buffer, size, NULL); unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, unit); g_object_unref(unit); container = gwy_container_new(); switch (imgfile.data_type) { case BURLEIGH_CURRENT: unit = gwy_si_unit_new("A"); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Current")); gwy_data_field_multiply(dfield, Picoampere); break; case BURLEIGH_TOPOGRAPHY: unit = gwy_si_unit_new("m"); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Topography")); gwy_data_field_multiply(dfield, Angstrom); break; default: unit = gwy_si_unit_new("m"); break; } gwy_data_field_set_si_unit_z(dfield, unit); g_object_unref(unit); gwy_container_set_object_by_name(container, "/0/data", dfield); g_object_unref(dfield); gwy_file_channel_import_log_add(container, 0, NULL, filename); return container; }
static void extract_path_do(GwyContainer *data, GwyDataField *dfield, gboolean realsquare, GwySelection *selection, const ExtrPathArgs *args) { GwyGraphModel *gmodel; GwySpline *spline; GwyXY *points, *tangents; GwySIUnit *xyunit; gdouble dx, dy, qx, qy, h, l, length, slackness; gdouble *xdata, *ydata; guint n, i; gboolean closed; /* This can only be satisfied in non-interactive use. Doing nothing is * the best option in this case. */ if (!selection || (n = gwy_selection_get_data(selection, NULL)) < 2) return; points = rescale_points(selection, dfield, realsquare, &dx, &dy, &qx, &qy); h = MIN(dx, dy); spline = gwy_spline_new_from_points(points, n); g_object_get(selection, "slackness", &slackness, "closed", &closed, NULL); gwy_spline_set_closed(spline, closed); gwy_spline_set_slackness(spline, slackness); g_free(points); length = gwy_spline_length(spline); /* This would give natural sampling for a straight line along some axis. */ n = GWY_ROUND(length + 1.0); points = g_new(GwyXY, n); tangents = g_new(GwyXY, n); xdata = g_new(gdouble, n); ydata = g_new(gdouble, n); gwy_spline_sample_uniformly(spline, points, tangents, n); qx *= dx; qy *= dy; for (i = 0; i < n; i++) { points[i].x *= qx; points[i].y *= qy; GWY_SWAP(gdouble, tangents[i].x, tangents[i].y); tangents[i].x *= qx; tangents[i].y *= -qy; l = sqrt(tangents[i].x*tangents[i].x + tangents[i].y*tangents[i].y); if (h > 0.0) { tangents[i].x /= l; tangents[i].y /= l; } xdata[i] = i/(n - 1.0)*length*h; } xyunit = gwy_data_field_get_si_unit_xy(dfield); if ((gmodel = create_graph_model(points, xdata, ydata, n, args->x, args->y))) { g_object_set(gmodel, "axis-label-left", _("Position"), "axis-label-bottom", _("Distance"), "si-unit-x", xyunit, "si-unit-y", xyunit, NULL); gwy_app_data_browser_add_graph_model(gmodel, data, TRUE); g_object_unref(gmodel); } if ((gmodel = create_graph_model(tangents, xdata, ydata, n, args->vx, args->vy))) { g_object_set(gmodel, "axis-label-left", _("Tangent"), "axis-label-bottom", _("Distance"), "si-unit-x", xyunit, NULL); gwy_app_data_browser_add_graph_model(gmodel, data, TRUE); g_object_unref(gmodel); } g_free(ydata); g_free(xdata); g_free(points); g_free(tangents); }
static gboolean aafm_export(G_GNUC_UNUSED GwyContainer *data, const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { union { guchar pp[4]; float f; } z; guint16 res, r; gint16 *x; gint16 v; gint i, j, xres, yres, n; GwyDataField *dfield; const gdouble *d; gdouble min, max, q, z0; FILE *fh; gboolean ok = TRUE; gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield, 0); if (!dfield) { err_NO_CHANNEL_EXPORT(error); return FALSE; } if (!(fh = gwy_fopen(filename, "wb"))) { err_OPEN_WRITE(error); return FALSE; } d = gwy_data_field_get_data_const(dfield); xres = gwy_data_field_get_xres(dfield); yres = gwy_data_field_get_yres(dfield); res = MIN(MIN(xres, yres), 32767); n = (gint)res*(gint)res; r = GUINT16_TO_LE(res); fwrite(&res, 1, sizeof(r), fh); gwy_data_field_get_min_max(dfield, &min, &max); if (min == max) { q = 0.0; z0 = 0.0; } else { q = 65533.0/(max - min); z0 = -32766.5*(max + min)/(max - min); } z.f = MIN(gwy_data_field_get_xreal(dfield), gwy_data_field_get_yreal(dfield))/Angstrom; #if (G_BYTE_ORDER == G_BIG_ENDIAN) GWY_SWAP(guchar, z.pp[0], z.pp[3]); GWY_SWAP(guchar, z.pp[1], z.pp[2]); #endif fwrite(&z, 1, sizeof(z), fh); x = g_new(gint16, n); for (i = 0; i < res; i++) { for (j = 0; j < res; j++) { v = GWY_ROUND(d[(res-1 - j)*res + i]*q + z0); x[i*res + j] = GINT16_TO_LE(v); } } if (!(ok = (fwrite(x, 1, 2*n, fh) == 2*n))) { err_WRITE(error); g_unlink(filename); } else { z.f = (max - min)/Angstrom; #if (G_BYTE_ORDER == G_BIG_ENDIAN) GWY_SWAP(guchar, z.pp[0], z.pp[3]); GWY_SWAP(guchar, z.pp[1], z.pp[2]); #endif fwrite(&z, 1, sizeof(z), fh); } fclose(fh); g_free(x); return ok; }
static void gwy_data_field_facet_distribution(GwyDataField *dfield, gint kernel_size, GwyContainer *container) { GwyDataField *dtheta, *dphi, *dist; GwySIUnit *siunit; gdouble *xd, *yd, *data; const gdouble *xdc, *ydc; gdouble q, max; gint res, hres, i, j, mi, mj, xres, yres; if (gwy_container_gis_object_by_name(container, "/theta", &dtheta)) g_object_ref(dtheta); else dtheta = gwy_data_field_new_alike(dfield, FALSE); if (gwy_container_gis_object_by_name(container, "/phi", &dphi)) g_object_ref(dphi); else dphi = gwy_data_field_new_alike(dfield, FALSE); compute_slopes(dfield, kernel_size, dtheta, dphi); xres = gwy_data_field_get_xres(dfield); yres = gwy_data_field_get_yres(dfield); xd = gwy_data_field_get_data(dtheta); yd = gwy_data_field_get_data(dphi); for (i = xres*yres; i; i--, xd++, yd++) { gdouble theta, phi; slopes_to_angles(*xd, *yd, &theta, &phi); *xd = theta; *yd = phi; } q = gwy_data_field_get_max(dtheta); q = MIN(q*1.05, G_PI/2.0); q = G_SQRT2/(2.0*sin(q/2.0)); if (gwy_container_gis_object_by_name(container, "/0/data", &dist)) { g_object_ref(dist); gwy_data_field_clear(dist); gwy_data_field_set_xreal(dist, 2.0*G_SQRT2/q); gwy_data_field_set_yreal(dist, 2.0*G_SQRT2/q); } else { dist = gwy_data_field_new(FDATA_RES, FDATA_RES, 2.0*G_SQRT2/q, 2.0*G_SQRT2/q, TRUE); siunit = gwy_si_unit_new(""); gwy_data_field_set_si_unit_z(dist, siunit); g_object_unref(siunit); /* FIXME */ siunit = gwy_si_unit_new(""); gwy_data_field_set_si_unit_xy(dist, siunit); g_object_unref(siunit); } res = FDATA_RES; hres = (res - 1)/2; data = gwy_data_field_get_data(dist); xdc = gwy_data_field_get_data_const(dtheta); ydc = gwy_data_field_get_data_const(dphi); for (i = xres*yres; i; i--, xdc++, ydc++) { gdouble x, y; gint xx, yy; angles_to_xy(*xdc, *ydc, &x, &y); xx = GWY_ROUND(q*x/G_SQRT2*hres) + hres; yy = GWY_ROUND(q*y/G_SQRT2*hres) + hres; data[yy*res + xx] += 1.0; } /* Find maxima */ mi = mj = hres; max = 0; for (i = 1; i+1 < res; i++) { for (j = 1; j+1 < res; j++) { gdouble z; z = data[i*res + j] + 0.3*(data[i*res + j - 1] + data[i*res + j + 1] + data[i*res - res + j] + data[i*res + res + j]) + 0.1*(data[i*res - res + j - 1] + data[i*res - res + j + 1] + data[i*res + res + j - 1] + data[i*res + res + j + 1]); if (G_UNLIKELY(z > max)) { max = z; mi = i; mj = j; } } } for (i = res*res; i; i--, data++) *data = pow(*data, 0.35); gwy_container_set_double_by_name(container, "/q", q); { gdouble x, y, theta, phi; x = (mj - hres)*G_SQRT2/(q*hres); y = (mi - hres)*G_SQRT2/(q*hres); xy_to_angles(x, y, &theta, &phi); gwy_container_set_double_by_name(container, "/theta0", theta); gwy_container_set_double_by_name(container, "/phi0", phi); } gwy_container_set_object_by_name(container, "/0/data", dist); g_object_unref(dist); gwy_container_set_object_by_name(container, "/theta", dtheta); g_object_unref(dtheta); gwy_container_set_object_by_name(container, "/phi", dphi); g_object_unref(dphi); gwy_container_set_string_by_name(container, "/0/base/palette", g_strdup(FVIEW_GRADIENT)); gwy_data_field_data_changed(dist); }
static void square_samples(GwyContainer *data, GwyRunType run) { GwyDataField *dfield, *dfields[3]; gdouble xreal, yreal, qx, qy; gint oldid, newid, xres, yres; GQuark quark; 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_ID, &oldid, 0); dfield = dfields[0]; xres = gwy_data_field_get_xres(dfield); yres = gwy_data_field_get_yres(dfield); xreal = gwy_data_field_get_xreal(dfield); yreal = gwy_data_field_get_yreal(dfield); qx = xres/xreal; qy = yres/yreal; if (fabs(log(qx/qy)) > 1.0/hypot(xres, yres)) { /* Resample */ if (qx < qy) xres = MAX(GWY_ROUND(xreal*qy), 1); else yres = MAX(GWY_ROUND(yreal*qx), 1); dfields[0] = gwy_data_field_new_resampled(dfields[0], xres, yres, GWY_INTERPOLATION_BSPLINE); if (dfields[1]) { dfields[1] = gwy_data_field_new_resampled(dfields[1], xres, yres, GWY_INTERPOLATION_ROUND); } if (dfields[2]) { dfields[2] = gwy_data_field_new_resampled(dfields[2], xres, yres, GWY_INTERPOLATION_BSPLINE); } } else { /* Ratios are equal, just duplicate */ dfields[0] = gwy_data_field_duplicate(dfields[0]); if (dfields[1]) dfields[1] = gwy_data_field_duplicate(dfields[1]); if (dfields[2]) dfields[2] = gwy_data_field_duplicate(dfields[2]); } newid = gwy_app_data_browser_add_data_field(dfields[0], data, TRUE); g_object_unref(dfields[0]); gwy_app_sync_data_items(data, data, oldid, newid, FALSE, GWY_DATA_ITEM_GRADIENT, GWY_DATA_ITEM_RANGE, GWY_DATA_ITEM_MASK_COLOR, 0); if (dfields[1]) { quark = gwy_app_get_mask_key_for_id(newid); gwy_container_set_object(data, quark, dfields[1]); g_object_unref(dfields[1]); } if (dfields[2]) { quark = gwy_app_get_show_key_for_id(newid); gwy_container_set_object(data, quark, dfields[2]); g_object_unref(dfields[2]); } gwy_app_channel_log_add_proc(data, oldid, newid); }