// Before placing a new label we need to see if the label overlaps over // previously placed labels. This algorithm will be refactored a bit to try // NE SE SW NW placements in the future. void try_and_insert_placement(simplet_lithograph_t *litho, PangoLayout *layout, double x, double y){ int width, height; // Find the computed width and height of a layout in image pixels pango_layout_get_pixel_size(layout, &width, &height); simplet_bounds_t *bounds = simplet_bounds_new(); if(!bounds) return; // Create a bounds to test for intersection simplet_bounds_extend(bounds, floor(x - width / 2), floor(y - height / 2)); simplet_bounds_extend(bounds, floor(x + width / 2), floor(y + height / 2)); // Iterate through the list of already placed labels and check for overlaps. simplet_listiter_t *iter = simplet_get_list_iter(litho->placements); placement_t *placement; while((placement = (placement_t *) simplet_list_next(iter))){ if(simplet_bounds_intersects(placement->bounds, bounds)){ simplet_bounds_free(bounds); g_object_unref(layout); simplet_list_iter_free(iter); return; } } // If we get here we can create and insert a new placement. placement_t *plc = placement_new(layout, bounds); if(!plc) { simplet_bounds_free(bounds); g_object_unref(layout); return; } simplet_list_push(litho->placements, (void *)plc); }
// Process a layer and add labels. simplet_status_t simplet_layer_process(simplet_layer_t *layer, simplet_map_t *map, simplet_lithograph_t *litho, cairo_t *ctx){ simplet_listiter_t *iter; OGRDataSourceH source; if(!(source = OGROpenShared(layer->source, 0, NULL))) return set_error(layer, SIMPLET_OGR_ERR, "error opening layer source"); // Retain the datasource because we want to cache open connections to a // data source like postgres. if(OGR_DS_GetRefCount(source) == 1) OGR_DS_Reference(source); if(!(iter = simplet_get_list_iter(layer->filters))){ OGRReleaseDataSource(source); return set_error(layer, SIMPLET_OOM, "out of memory getting list iterator"); } // Loop through the layer's filters and process them. simplet_filter_t *filter; simplet_status_t status = SIMPLET_OK; while((filter = simplet_list_next(iter))) { status = simplet_filter_process(filter, map, source, litho, ctx); if(status != SIMPLET_OK){ simplet_list_iter_free(iter); OGRReleaseDataSource(source); return status; } simplet_lithograph_apply(litho, filter->styles); } OGRReleaseDataSource(source); return SIMPLET_OK; }
// Apply the labels to the map. void simplet_lithograph_apply(simplet_lithograph_t *litho, simplet_list_t *styles){ simplet_listiter_t *iter = simplet_get_list_iter(litho->placements); placement_t *placement; cairo_save(litho->ctx); while((placement = (placement_t *) simplet_list_next(iter))){ if(placement->placed == TRUE) continue; cairo_move_to(litho->ctx, placement->bounds->nw.x, placement->bounds->se.y); // Draw the placement pango_cairo_layout_path(litho->ctx, placement->layout); placement->placed = TRUE; } simplet_apply_styles(litho->ctx, styles, "text-stroke-weight", "text-stroke-color", "color", NULL); // Apply and draw various outline options. cairo_restore(litho->ctx); }