colinjstewart
colinjstewart

Reputation: 69

Polygon edge gradient algorithm

I'm trying to create an application that uses an uncommon polygon gradient fill. The idea is that each edge of the polygon has a single colour, and these edge colours are used to fill the rest of the polygon's pixels in a smooth gradient.

I have a working program that performs this gradient by determining, for each pixel, how far it is from all the polygon's edges and doing a weighted average of all the edges' colours based on the distances to them. Here's a sample output:

Polygon edge gradient sample (click link to view)

The problem is that the algorithm is horribly slow when the polygon has a lot of edges, namely because for every single pixel, it has to calculate distances to every edge. Any ideas for how this could be sped up?

Current algorithm:

for pixel in polygon: # predetermined using a basic scan-line polygon-fill algorithm
    edge_distances = {}
    for edge in polygon:
        distance = calc_point_to_line_distance(pixel, edge) # simple formula, constant time            
        edge_distances[edge] = distance
    colour = calc_pixel_colour(edge_distances)  # runs in O(num_edges) time
    set_pixel_colour(pixel, colour)

I've left out the details because I'm looking for big picture ideas of how to do this better (i.e. better than O(num_pixels*num_edges)). All ideas welcome.

Thanks!

Upvotes: 4

Views: 597

Answers (2)

colinjstewart
colinjstewart

Reputation: 69

Thanks to @SirRaffleBuffle for pointing me towards the answer (sorry, I don't have enough "reputation points" to upvote you).

What I went with in the end was a colour diffusion algorithm, combined with a multi-grid solver for massive performance gains (described mathematically here, here, and here; warning, lots of opaque math jargon and Greek letters).

The diffusion algorithm is fairly straightforward. You start with a canvas of pixels where some of them have specified colours (e.g. specified by you). Then, you start spreading the colours throughout the rest of the canvas by, for each pixel, averaging the four adjacent (non-diagonal) pixels. You then repeat this process over and over until all the pixels are filled and their colours stabilize.

This process is pretty slow in itself, but can be dramatically sped up with a "multi-grid solver." Here, you initially run the diffusion on a very small canvas (i.e. low resolution), then map the output colours to a second canvas with double the resolution, and run the diffusion on this canvas. This process can be repeated at higher and higher resolutions until you get what you want. The idea is to initialize the diffusion process with pixel colours that are close to the final output, thus cutting through most of the algorithm's work.

This is a pretty crude explanation; let me know if you want more detail.

Upvotes: 2

Aki Suihkonen
Aki Suihkonen

Reputation: 20037

The distance calculation is easy to optimize: the distance(x,y, edge_i) - distance(x+A,y+B, edge_i) is constant. This part of the algorithm can be reduced to single addition per pixel per edge. Further optimizations (if any) depend on the pixel color determining function.

Upvotes: 0

Related Questions