 more useful options PerlMonks

### Re: Re: Perl Spots

by YuckFoo (Abbot)
 on Aug 14, 2002 at 21:35 UTC ( #190245=note: print w/replies, xml ) Need Help??

in reply to Re: Perl Spots

Thanks for the extension hossman++. This works pretty good. Only problem is, I gave you a very sub-optimal algorithm. Ok for 40 x 80, too slow for 200 x 200.

The big kludge was adding 8 points in adjacent squares. This isn't necessary. Instead calculate the x and y distances separately. If a distance is greater than .5, adjust it to 1 - distance. If a point is .7 from a v-point, it is .3 from a corresponding v-point in an adjacent square.

This means about 90% fewer v-points to test against, so this is many times faster.

So here's another version based on your changes with an additional color option.

YuckFoo

```#!/usr/bin/perl

use strict;
use GD;

my \$ROWS   = 200;            # number of rows
my \$COLS   = 200;            # number of columns
my \$POINTS = 12;             # number of Voronoi points
my \$COLORS = 128;            # number of colors

my \$INNER = [255, 255,   0]; # inner color (red, green, blue)
my \$OUTER = [  0,  32,   0]; # outer color (red, green, blue)

my \$xfact = 1 / \$COLS;
my \$yfact = 1 / \$ROWS;

# Allocate some colors
my \$img = new GD::Image(\$COLS, \$ROWS);
my \$colors = makecolors(\$img, \$COLORS, \$INNER, \$OUTER);

my (@xs, @ys);

# Pick some random points
for (0..\$POINTS-1) {
push (@xs, rand());
push (@ys, rand());
}

# Calculate screen
for my \$yi (0..\$ROWS-1) {
my \$y = \$yi * \$yfact;
for my \$xi (0..\$COLS-1) {
my \$x = \$xi * \$xfact;
my (\$best, \$good) = closest(\$x, \$y, \@xs, \@ys);

\$img->setPixel(\$xi, \$yi, \$colors->[\$COLORS * (\$best / \$good)]
+);
}
}

binmode STDOUT;
print \$img->png();
#-----------------------------------------------------------
sub closest {

my (\$x, \$y, \$xs, \$ys) = @_;
my (\$dist, \$best, \$good);

for (my \$i = 0; \$i < @\$xs; \$i++) {
my \$xdiff = abs(\$x - \$xs->[\$i]);
my \$ydiff = abs(\$y - \$ys->[\$i]);

if (\$xdiff > .5) { \$xdiff = 1 - \$xdiff; }
if (\$ydiff > .5) { \$ydiff = 1 - \$ydiff; }

\$dist = sqrt(\$xdiff * \$xdiff + \$ydiff * \$ydiff);

if    (\$i == 0 || \$dist < \$best) { (\$good, \$best) = (\$best, \$dis
+t); }
elsif (\$i == 1 || \$dist < \$good) { \$good = \$dist; }
}

return (\$best, \$good);
}

#-----------------------------------------------------------
sub makecolors {

my (\$img, \$num, \$beg, \$end) = @_;
my (@colors);

my \$red   = (\$end-> - \$beg->) / \$num;
my \$green = (\$end-> - \$beg->) / \$num;
my \$blue  = (\$end-> - \$beg->) / \$num;

for (my \$i = 0; \$i < \$num; \$i++) {
\$beg-> += \$red;
\$beg-> += \$green;
\$beg-> += \$blue;
push (@colors, \$img->colorAllocate(@\$beg));
}

return \@colors;
}

Replies are listed 'Best First'.
Re: Re: Re: Perl Spots
by hossman (Prior) on Aug 15, 2002 at 05:49 UTC
one other things you should change now that the size is a couple of orders of magnitude bigger...
```# Calculate screen
for my \$yi (0..\$ROWS-1) {
my \$y = \$yi * \$yfact;
for my \$xi (0..\$COLS-1) {
...
}
}

Should be something like...

```# Calculate screen
for (my \$yi = 0; \$yi < \$ROWS; \$yi++) {
my \$y = \$yi * \$yfact;
for (my \$xi = 0; \$xi < \$COLS; \$xi++) {
...
}
}

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://190245]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (2)
As of 2022-05-20 05:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
Do you prefer to work remotely?

Results (72 votes). Check out past polls.

Notices?