Beefy Boxes and Bandwidth Generously Provided by pair Networks vroom
Keep It Simple, Stupid
 
PerlMonks

RFC: Creating unicursal stars

by Fox (Acolyte)
 | Log in | Create a new user | The Monastery Gates | Super Search | 
 | Seekers of Perl Wisdom | Meditations | PerlMonks Discussion | 
 | Obfuscation | Reviews | Cool Uses For Perl | Perl News | Q&A | Tutorials | 
 | Poetry | Recent Threads | Newest Nodes | Donate | What's New | 

on Nov 06, 2009 at 14:17 UTC ( #805492=perlmeditation: print w/ replies, xml ) Need Help??

All started a week ago when I saw a unicursal hexagram and I started wondering the logic behind drawing a n-points unicursal star, so I gone thorough some wikipedia articles and finally created a method that can draw a unicursal star polygon of n points for any natural* number.

For those wondering, any non-convex polygon in star form could be considered a star polygon, but only those where the lines can be draw starting and ending at the same point, passing through all the other points exactly one time are unicursal star polygons

Although my code works like I wanted, I still don't like how it does it, so I would like to hear what the perlmonks have to say about it.


And here is the code:

#!/usr/bin/perl use warnings; die "need number of points\n" unless @ARGV; $n = shift; die "need valid number\n" if($n!~m/^\d+$/ || $n < 1); use constant PI => 4*atan2(1,1); $rad = 150; # radius of circunference, size of star $alpha = 3*PI/2; # angle of starting point $beta = 2*PI/$n; # angle variation for(0..$n-1) # finding necessary points { $x = $rad + $rad * cos($alpha); $y = $rad + $rad * sin($alpha); $pts{$_}{x} = $x; $pts{$_}{y} = $y; $alpha += $beta; } # svg header print "<?xml version='1.0' standalone='no'?> <!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'> <svg width='100%' height='100%' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\n"; $mod = calcMagic($n); # interval of points print STDERR "mod: $mod\n"; $oldp = 0; $p = 1; while($p != 0) { $mod = hexMagic($oldp) if($n == 6); # hexagrams are irregular $p = ($oldp + $mod) % $n; # find next point print STDERR "LINE: $oldp <-> $p\n"; $x1 = $pts{$oldp}{x}; $y1 = $pts{$oldp}{y}; $x2 = $pts{$p}{x}; $y2 = $pts{$p}{y}; print "<line x1='$x1' y1='$y1' x2='$x2' y2='$y2' style='stroke:rgb +(0,0,0);stroke-width:1'/>\n"; $oldp = $p; } print "\n</svg>\n"; # calculate the interval # based on number of points sub calcMagic { ($n) = @_; $m = -1; $mod = 1; for(1..$n) { $mod += $m; $m = nextMagic($m); } return $mod; } # have no idea sub nextMagic { ($oldm) = @_; return 3 if($oldm == -1); return -2 if($oldm == 3); return 2 if($oldm == -2); return -1 if($oldm == 2); } # special case, # hexagram intervals sub hexMagic { ($p) = @_; return 2 if($p == 0); return 3 if($p == 2); return 4 if($p == 5); return 4 if($p == 3); return 3 if($p == 1); return 2 if($p == 4); }

As you can see, it actually outputs a SVG image, you can run it like:
$perl draw_star.pl N > img.svg ,where N is the points number
and open the result in your favorite browser/image viewer.

The main problem is finding the $mod number, this is how much points it will 'jump' from the current point to draw the next line.
Notice that this is where things get dirty, calcMagic was called this ways because I failed in understand the logic(if any) behind it.

There is also a side problem, take a look again in the unicursal hexagram and you will notice that it's irregular, which means the $mod number changes depending on the current point.

..and, although I was a Anonymous Monk for quite a time, I sill not sure if this is the right place for this, even after reading Where should I post X?, so I'm sorry if it isn't.

Comment on RFC: Creating unicursal stars
Select or Download Code
Re: RFC: Creating unicursal stars
by huxtonr (Initiate) on Nov 06, 2009 at 16:27 UTC

    The main problem isn't finding $mod, it's getting it to work, and you've done that. Congratulations!

    However, there are a couple of things you might find it useful to change.

    Firstly, "use strict" at the top of your script. Always. Until you know enough to ignore that advice.

    Secondly, try having a short main body of code calling a couple of top-level functions:

    #!/usr/bin/perl ... my @polygon = build_polygon($num_points, $radius); print_svg_polygon(@polygon); exit; sub build_polygon { ...

    It makes it easy to see what the script does at a glance, and lets you re-use bits more easily.

    Thirdly, make sure you scope your variables. Use "my" to restrict them to their defining block. Otherwise, the $n in calcMagic for example is the same as the $n at the top of your script. If you changed it inside the sub it would change in the main script too.

    sub calcMagic { my ($n) = @_; my $m = -1; my $mod = 1; for(1..$n) { $mod += $m; $m = nextMagic($m); } return $mod; }

    Finally, read up on Getopt::Long (http://search.cpan.org/~jv/Getopt-Long-2.38/lib/Getopt/Long.pm). That will let you call add named options to your script so you can do something like:

    draw_star.pl --points=5 --radius=200

    It's a well-known and well tested module, and has good documentation.

    You could also replace the multiple "if" statements with a lookup into an array, but I'm not sure it would make the code any clearer really.

    Hope that's helpful.

[reply]
[d/l]
[select]
[reply]

        That template is from 2000 (we're three versions of Perl past that time), was probably mostly developed even earlier, and while tye's advice is generally to be preferred over mine, I would call camelCase bad—or at the most defensible least, uncommon—Perl style.

[reply]
      thanks for the tips, will try to put it in practice ;)
[reply]
[d/l]
Re: RFC: Creating unicursal stars
by zentara (Chancellor) on Nov 06, 2009 at 18:23 UTC
[reply]
      this SuperFormula looks interesting indeed, will try to make a version using this formula and see if it gets any better.thanks.
[reply]
Re: RFC: Creating unicursal stars
by hossman (Parson) on Nov 07, 2009 at 08:47 UTC

    "Unicursal" ? ... "Eulerian path" ? ... "Star polygon" ? ....

    I never knew they had a real name, i just thought they were kinda cool: Make N pointed stars.

[reply]
      haha, neither I, I learned all about it past week in wikipedia
[reply]

Back to Meditations


Login:
Password
remember me
What's my password?
Create A New User

Node Status
node history
Node Type: perlmeditation [id://805492]
Front-paged by Arunbear
help
Community Ads
Chatterbox
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users
Others about the Monastery: (10)
GrandFather
atcroft
herveus
Eyck
hipowls
biohisham
djp
gnosti
rastoboy
im2
As of 2009-11-21 10:01 GMT
Sections
The Monastery Gates
Seekers of Perl Wisdom
Meditations
PerlMonks Discussion
Categorized Q&A
Tutorials
Obfuscated Code
Perl Poetry
Cool Uses for Perl
Perl News
Information
PerlMonks FAQ
Guide to the Monastery
What's New at PerlMonks
Voting/Experience System
Tutorials
Reviews
Library
Perl FAQs
Other Info Sources
Find Nodes
Nodes You Wrote
Super Search
List Nodes By Users
Newest Nodes
Recently Active Threads
Selected Best Nodes
Best Nodes
Worst Nodes
Saints in our Book
Leftovers
The St. Larry Wall Shrine
Offering Plate
Awards
Craft
Snippets Section
Code Catacombs
Quests
Editor Requests
Buy PerlMonks Gear
PerlMonks Merchandise
Planet Perl
Perlsphere
Use Perl
Perl.com
Perl 5 Wiki
Perl Jobs
Perl Mongers
Perl Directory
Perl documentation
CPAN
Random Node
Voting Booth

Future historians will find that the material characteristic of the current era is...

Aluminium
Plastic
Oil
Water
Carbon dioxide
Copper
Iron
Silicon
Salt
Uranium
Hydrogen
Other

Results (729 votes), past polls