vertex_hashtable* vertex_hashtable_new(int table_size) { vertex_hashtable* ht = malloc(sizeof(vertex_hashtable)); ht->items = malloc( sizeof(vertex_bucket) * table_size ); ht->table_size = table_size; for(int i = 0; i < ht->table_size; i++) { ht->items[i].keys = vertex_list_new(); ht->items[i].values = int_list_new(); } return ht; }
static void inscribed_discs_and_friends(gdouble *inscrdrvalues, gdouble *inscrdxvalues, gdouble *inscrdyvalues, gdouble *edmeanvalues, const gdouble *xvalues, const gdouble *yvalues, const guint *grains, const guint *sizes, guint ngrains, const GwyMaskField *mask, gdouble dx, gdouble dy) { enum { NCAND_MAX = 15 }; g_return_if_fail(grains); g_return_if_fail(sizes); g_return_if_fail(xvalues); g_return_if_fail(yvalues); g_return_if_fail(GWY_IS_MASK_FIELD(mask)); g_return_if_fail(inscrdrvalues || inscrdxvalues || inscrdyvalues || edmeanvalues); const GwyFieldPart *bbox = gwy_mask_field_grain_bounding_boxes(mask); guint xres = mask->xres; gdouble qgeom = sqrt(dx*dy); gboolean nodiscs = !inscrdrvalues && !inscrdxvalues && !inscrdyvalues; guint *grain = NULL, *workspace = NULL; guint grainsize = 0; IntList *inqueue = int_list_new(0); IntList *outqueue = int_list_new(0); GArray *candidates = g_array_new(FALSE, FALSE, sizeof(FooscribedDisc)); GArray *vertices = g_array_new(FALSE, FALSE, sizeof(guint)); EdgeList edges = { 0, 0, NULL }; /* * For each grain: * Extract it, find all boundary pixels. * Use (octagnoal) erosion to find disc centre candidate(s). * For each candidate: * Find maximum disc that fits with this centre. * By expanding/moving try to find a larger disc until we cannot * improve it. */ for (guint gno = 1; gno <= ngrains; gno++) { guint w = bbox[gno].width, h = bbox[gno].height; gdouble xoff = dx*bbox[gno].col, yoff = dy*bbox[gno].row; /* If the grain is rectangular, calculate the properties directly. * Large rectangular grains are rare but the point is to catch * grains with width or height of 1 here. */ if (sizes[gno] == w*h) { gdouble sdx = 0.5*w*dx, sdy = 0.5*h*dy; gdouble Lmax = fmax(sdx, sdy), Lmin = fmin(sdx, sdy); if (inscrdrvalues) inscrdrvalues[gno] = 0.999999*Lmin; if (inscrdxvalues) inscrdxvalues[gno] = sdx + xoff; if (inscrdyvalues) inscrdyvalues[gno] = sdy + yoff; if (edmeanvalues) edmeanvalues[gno] = Lmin/6.0*(3.0 - Lmin/Lmax); continue; } /* Upsampling twice combined with octagonal erosion has the nice * property that we get candidate pixels in places such as corners * or junctions of one-pixel thin lines. */ guint width, height, wspsize = grainsize; grain = extract_upsampled_square_pixel_grain(grains, xres, gno, bbox + gno, grain, &grainsize, &width, &height, dx, dy); workspace = grain_maybe_realloc(workspace, width, height, &wspsize); g_assert(wspsize == grainsize); /* Size of upsampled pixel in original squeezed pixel coordinates. * Normally equal to 1/2 and always approximately 1:1. */ gdouble sdx = w*(dx/qgeom)/width; gdouble sdy = h*(dy/qgeom)/height; /* Grain centre in squeezed pixel coordinates within the bbox. */ gdouble centrex = (xvalues[gno] + 0.5)*(dx/qgeom); gdouble centrey = (yvalues[gno] + 0.5)*(dy/qgeom); _gwy_distance_transform_raw(grain, workspace, width, height, TRUE, inqueue, outqueue); if (edmeanvalues) { edmeanvalues[gno] = mean_euclidean_distance(grain, width*height, w*dx/width, h*dy/height); } if (nodiscs) continue; #if 0 g_printerr("Grain #%u, orig %ux%u, resampled to %ux%u\n", gno, bbox[gno].width, bbox[gno].height, width, height); for (guint i = 0; i < height; i++) { for (guint j = 0; j < width; j++) { if (!grain[i*width + j]) g_printerr(".."); else g_printerr("%02u", grain[i*width + j]); g_printerr("%c", j == width-1 ? '\n' : ' '); } } #endif double dist = find_disc_centre_candidates(candidates, NCAND_MAX, grain, width, height, sdx, sdy, centrex, centrey); find_all_edges(&edges, vertices, grains, xres, gno, bbox + gno, dx/qgeom, dy/qgeom); /* Try a few first candidates for the inscribed disc centre. */ FooscribedDisc *cand; for (guint i = 0; i < candidates->len; i++) { cand = &g_array_index(candidates, FooscribedDisc, i); improve_inscribed_disc(cand, &edges, dist); } cand = &g_array_index(candidates, FooscribedDisc, 0); for (guint i = 1; i < candidates->len; i++) { if (g_array_index(candidates, FooscribedDisc, i).R2 > cand->R2) cand = &g_array_index(candidates, FooscribedDisc, i); } if (inscrdrvalues) inscrdrvalues[gno] = sqrt(cand->R2)*qgeom; if (inscrdxvalues) inscrdxvalues[gno] = cand->x*qgeom + xoff; if (inscrdyvalues) inscrdyvalues[gno] = cand->y*qgeom + yoff; //g_printerr("[%u] %g %g %g\n", gno, sqrt(cand->R2)*qgeom, cand->x*qgeom + xoff, cand->y*qgeom + yoff); } g_free(workspace); g_free(grain); int_list_free(inqueue); int_list_free(outqueue); g_free(edges.edges); g_array_free(vertices, TRUE); g_array_free(candidates, TRUE); }