Keith Vetter 2003-03-06 - if you take a 3D solid shape--a polyhedron--and cut along certain edges and lay the whole thing flat the result is called a polyhedron map.
Conversely, you can take a polyhedron map, print it, cut it out, fold along the lines and attach at the tabs to create paper models of polyhedra.
This whizzlet has polyhedron nets for all five Platonic solids and several of the thirteen Archimedean solids. You can change the coloring scheme by selecting a new color and clicking on a polygon. Printing, not one of tk's strong points, is only partially implemented: it will generate a postscript file for you--you have to use some other tool to print it.
##+########################################################################## # # poly.tcl -- Draws polyhedron nets that you can print out, cut out, fold and # join tabs to construct your own polyhedra. See http://www.korthalsaltes.com # by Keith Vetter, March 5, 2003 # package require Tk set S(bwidget) [expr {! [catch {package require BWidget}]}] ;# For combobox set S(title) "Polyhedron Nets" # Info for each polyhedron: # name,I => {<# faces> <tab size>} # name,# {<face polygon type> <where> <sides w/ tabs> <color>} # where => EITHER <angle for side 0> OR {<neighbor face #> <attach side>} array set POLY { Tetrahedron,I {4 .1} Tetrahedron,0 {t 60 {0 2} blue} Tetrahedron,1 {t {0 1} {} yellow} Tetrahedron,2 {t {1 1} {} red} Tetrahedron,3 {t {2 2} {2} green} Cube,I {6 .2} Cube,0 {s 0 {} yellow} Cube,1 {s {0 1} {} blue} Cube,2 {s {0 2} {1 3} red} Cube,3 {s {2 2} {1 2} yellow} Cube,4 {s {0 3} {2} blue} Cube,5 {s {0 0} {1 3} red} Octahedron,I {8 .2} Octahedron,0 {t 60 {} red} Octahedron,1 {t {0 1} {} yellow} Octahedron,2 {t {1 1} {} cyan} Octahedron,3 {t {2 2} {} blue} Octahedron,4 {t {3 1} {} green} Octahedron,5 {t {0 2} {2} violet} Octahedron,6 {t {1 2} {1 2} orange} Octahedron,7 {t {2 1} {1 2} purple} Icosahedron,I {20 .2} Icosahedron,0 {t 60 {1} red} Icosahedron,1 {t {0 0} {} blue} Icosahedron,2 {t {1 2} {1} cyan} Icosahedron,3 {t {1 1} {1} green} Icosahedron,4 {t {2 2} {1} green} Icosahedron,5 {t {4 2} {} yellow} Icosahedron,6 {t {5 1} {} blue} Icosahedron,7 {t {6 1} {2} cyan} Icosahedron,8 {t {7 1} {2} red} Icosahedron,9 {t {3 2} {1} red} Icosahedron,10 {t {9 2} {} yellow} Icosahedron,11 {t {10 1} {} blue} Icosahedron,12 {t {11 1} {2} green} Icosahedron,13 {t {12 1} {2} cyan} Icosahedron,14 {t {0 2} {1} cyan} Icosahedron,15 {t {14 2} {} yellow} Icosahedron,16 {t {15 1} {} blue} Icosahedron,17 {t {16 1} {} red} Icosahedron,18 {t {17 1} {2} green} Icosahedron,19 {t {17 2} {} yellow} Dodecahedron,I {12 .2} Dodecahedron,0 {p 108 {} yellow} Dodecahedron,1 {p {0 0} {4} blue} Dodecahedron,2 {p {0 1} {4} red} Dodecahedron,3 {p {0 2} {4} blue} Dodecahedron,4 {p {0 3} {4} green} Dodecahedron,5 {p {0 4} {4} red} Dodecahedron,6 {p {1 3} {2 3 4} yellow} Dodecahedron,7 {p {2 3} {3 4} green} Dodecahedron,8 {p {4 3} {2 3 4} yellow} Dodecahedron,9 {p {3 3} {2 3 4} red} Dodecahedron,10 {p {5 3} {2 3 4} green} Dodecahedron,11 {p {7 2} {} blue} Cubeoctahedron,I {14 .2} Cubeoctahedron,0 {s 90 {} yellow} Cubeoctahedron,1 {t {0 2} {} blue} Cubeoctahedron,2 {s {1 2} {3} yellow} Cubeoctahedron,3 {t {2 2} {1 2} blue} Cubeoctahedron,4 {t {0 1} {} blue} Cubeoctahedron,5 {s {4 2} {3} yellow} Cubeoctahedron,6 {t {5 2} {1 2} blue} Cubeoctahedron,7 {t {0 0} {} blue} Cubeoctahedron,8 {s {7 2} {3} yellow} Cubeoctahedron,9 {t {8 2} {1 2} blue} Cubeoctahedron,10 {t {0 3} {} blue} Cubeoctahedron,11 {s {10 2} {3} yellow} Cubeoctahedron,12 {t {11 2} {2} blue} Cubeoctahedron,13 {s {12 1} {} yellow} Truncated\ Tetrahedron,I {8 .2} Truncated\ Tetrahedron,0 {h 120 {} green} Truncated\ Tetrahedron,1 {h {0 0} {3 4 5} blue} Truncated\ Tetrahedron,2 {t {0 1} {2} yellow} Truncated\ Tetrahedron,3 {h {0 2} {4 5} cyan} Truncated\ Tetrahedron,4 {t {3 3} {} yellow} Truncated\ Tetrahedron,5 {t {0 3} {2} yellow} Truncated\ Tetrahedron,6 {h {0 4} {3 4 5} red} Truncated\ Tetrahedron,7 {t {0 5} {2} yellow} Rhombicuboctahedron,I {26 .2} Rhombicuboctahedron,0 {s 180 {0} green} Rhombicuboctahedron,1 {t {0 1} {1} blue} Rhombicuboctahedron,2 {t {0 3} {2} blue} Rhombicuboctahedron,3 {s {0 2} {} red} Rhombicuboctahedron,4 {s {3 1} {1 2} green} Rhombicuboctahedron,5 {s {3 3} {2 3} green} Rhombicuboctahedron,6 {s {3 2} {} green} Rhombicuboctahedron,7 {t {6 1} {1} blue} Rhombicuboctahedron,8 {t {6 3} {2} blue} Rhombicuboctahedron,9 {s {6 2} {} red} Rhombicuboctahedron,10 {s {9 1} {1} green} Rhombicuboctahedron,11 {s {9 3} {3} green} Rhombicuboctahedron,12 {s {10 2} {} red} Rhombicuboctahedron,13 {s {11 2} {} red} Rhombicuboctahedron,14 {s {9 2} {} green} Rhombicuboctahedron,15 {t {14 1} {1} blue} Rhombicuboctahedron,16 {t {14 3} {2} blue} Rhombicuboctahedron,17 {s {14 2} {} red} Rhombicuboctahedron,18 {s {17 1} {1 2} green} Rhombicuboctahedron,19 {s {17 3} {2 3} green} Rhombicuboctahedron,20 {s {17 2} {} green} Rhombicuboctahedron,21 {t {20 1} {1} blue} Rhombicuboctahedron,22 {t {20 3} {2} blue} Rhombicuboctahedron,23 {s {20 2} {} red} Rhombicuboctahedron,24 {s {23 1} {1 2} green} Rhombicuboctahedron,25 {s {23 3} {2 3} green} Truncated\ Octahedron,I {14 .2} Truncated\ Octahedron,0 {h 180 {1 5} green} Truncated\ Octahedron,1 {h {0 3} {} cyan} Truncated\ Octahedron,2 {s {0 0} {} yellow} Truncated\ Octahedron,3 {s {1 1} {1 2} yellow} Truncated\ Octahedron,4 {s {1 3} {2} yellow} Truncated\ Octahedron,5 {s {1 5} {2 3} yellow} Truncated\ Octahedron,6 {h {1 2} {1 2 3 4 5} blue} Truncated\ Octahedron,7 {h {1 4} {1 2 3 4 5} red} Truncated\ Octahedron,8 {h {2 2} {} cyan} Truncated\ Octahedron,9 {s {8 2} {1} yellow} Truncated\ Octahedron,10 {s {8 4} {3} yellow} Truncated\ Octahedron,11 {h {8 1} {1} blue} Truncated\ Octahedron,12 {h {8 3} {1 5} green} Truncated\ Octahedron,13 {h {8 5} {} red} Truncated\ Cube,I {14 .4} Truncated\ Cube,0 {o 180 {0 1 5 6 7} yellow} Truncated\ Cube,1 {t {0 2} {} red} Truncated\ Cube,2 {t {0 4} {} red} Truncated\ Cube,3 {o {1 1} {} cyan} Truncated\ Cube,4 {t {3 2} {} red} Truncated\ Cube,5 {t {3 4} {} red} Truncated\ Cube,6 {t {3 6} {} red} Truncated\ Cube,7 {o {2 2} {} cyan} Truncated\ Cube,8 {o {0 3} {1 2 3 6 7} green} Truncated\ Cube,9 {o {8 4} {1 2 3 6 7} yellow} Truncated\ Cube,10 {o {9 4} {1 3 6 7} green} Truncated\ Cube,11 {t {8 5} {2} red} Truncated\ Cube,12 {t {9 5} {2} red} Truncated\ Cube,13 {t {10 5} {2} red} Truncated\ Cubeoctahedron,I {22 .4} Truncated\ Cubeoctahedron,0 {o 180 {0 1 7} cyan} Truncated\ Cubeoctahedron,1 {s {0 2} {1} yellow} Truncated\ Cubeoctahedron,2 {o {1 2} {} cyan} Truncated\ Cubeoctahedron,3 {s {0 6} {3} yellow} Truncated\ Cubeoctahedron,4 {o {3 2} {} cyan} Truncated\ Cubeoctahedron,5 {s {0 4} {} yellow} Truncated\ Cubeoctahedron,6 {h {5 1} {1 2 3} red} Truncated\ Cubeoctahedron,7 {h {5 3} {3 4 5} red} Truncated\ Cubeoctahedron,8 {o {5 2} {1 7} cyan} Truncated\ Cubeoctahedron,9 {s {8 2} {1 2} yellow} Truncated\ Cubeoctahedron,10 {s {8 6} {2 3} yellow} Truncated\ Cubeoctahedron,11 {s {8 4} {} yellow} Truncated\ Cubeoctahedron,12 {h {11 1} {1 2 3} red} Truncated\ Cubeoctahedron,13 {h {11 3} {3 4 5} red} Truncated\ Cubeoctahedron,14 {o {11 2} {1 7} cyan} Truncated\ Cubeoctahedron,15 {s {14 2} {1 2} yellow} Truncated\ Cubeoctahedron,16 {s {14 6} {2 3} yellow} Truncated\ Cubeoctahedron,17 {s {14 4} {} yellow} Truncated\ Cubeoctahedron,18 {h {17 1} {1 2 3} red} Truncated\ Cubeoctahedron,19 {h {17 3} {3 4 5} red} Truncated\ Cubeoctahedron,20 {o {17 2} {1 7} cyan} Truncated\ Cubeoctahedron,21 {s {20 2} {1 2} yellow} Truncated\ Cubeoctahedron,22 {s {20 6} {2 3} yellow} } #set len [llength [array names POLY "Truncated\ Cubeoctahedron,*"]] #set POLY(Truncated\ Cubeoctahedron,I) [list [incr len -1] .3] ;# Exterior angle and sides for various polygons array set polygon {t {120 3} s {90 4} p {72 5} h {60 6} o {45 8}} proc DoDisplay {} { wm title . $::S(title) pack [frame .ctrl -relief ridge -bd 2 -padx 5 -pady 5] \ -side right -fill both -ipady 5 pack [frame .top -relief raised -bd 2] -side top -fill x pack [frame .screen -bd 2 -relief raised] -side top -fill both -expand 1 canvas .c -relief raised -borderwidth 0 -height 500 -width 500 \ -highlightthickness 0 label .msg -bg [.c cget -bg] -bd 2 -highlightthickness 0 \ -textvariable S(type) -font {{Times Roman} 18 bold} pack .msg -in .screen -side top -fill x -expand 0 pack .c -in .screen -side top -fill both -expand 1 set ::S(color) blue set colors {red orange yellow green darkblue blue cyan purple violet white} lappend colors [lindex [.c config -bg] 3] black foreach color $colors { radiobutton .top.b$color -width 1 -padx 0 -pady 0 -bg $color \ -variable ::S(color) -value $color } eval pack [winfo children .top] -side left -fill y bind .c <Configure> {CanvasCenter %W %h %w} bind all <Alt-c> {console show} DoCtrlFrame update } proc DoCtrlFrame {} { global S label .ltype -text "Polyhedron Type" .ltype configure -width 15 \ -font "[font actual [.ltype cget -font]] -weight bold" if {$S(bwidget)} { ComboBox .type -textvariable S(type) -editable 0 -values [GetPTypes] \ -exportselection 0 -justify center -takefocus 0 grid .ltype - -in .ctrl -row 1 -sticky ew grid .type - -in .ctrl -row 2 -sticky ew } else { eval tk_optionMenu .type S(type) [GetPTypes] .type configure -width 20 -font [.ltype cget -font] grid .type - -in .ctrl -row 1 -sticky ew } trace add variable S(type) write DrawNet button .next -text Next -command {NextPoly 1} button .prev -text Prev -command {NextPoly -1} set txt "Print on heavy paper.\nFold all lines backwards." append txt "\nAttach the white tabs." label .instr -text $txt -font [.ltype cget -font] -justify left -anchor w button .post -text PostScript -command PrintIt button .about -text About -command About grid .prev .next -in .ctrl -sticky ew grid rowconfigure .ctrl 20 -minsize 100 grid .instr - -in .ctrl -row 21 grid rowconfigure .ctrl 50 -weight 1 grid .post - -in .ctrl -row 100 -sticky ew grid .about - -in .ctrl -row 101 -sticky ew } proc GetPTypes {} { set ptypes {Tetrahedron Cube Octahedron Icosahedron Dodecahedron} foreach a [lsort -dictionary [array names ::POLY *,I]] { set type [lindex [split $a ","] 0] if {[lsearch $ptypes $type] > -1} continue ;# No duplicates lappend ptypes $type } return $ptypes } proc CanvasCenter {W h w} { foreach h [expr {$h / 2.0}] w [expr {$w / 2.0}] break $W config -scrollregion [list -$w -$h $w $h] ScaleIt } # DrawNet -- draws the net for the current polyhedron proc DrawNet {args} { global POLY V S .c delete all catch {unset V} foreach {faces S(tabsize)} $POLY($S(type),I) break set S(len) 100 for {set face 0} {$face < $faces} {incr face} { foreach {type where} $POLY($S(type),$face) break GetVertices $type $where $face } CenterNet ;# Shift to center net image DrawFaces $S(type) DrawTabs $S(type) ScaleIt } proc DrawFaces {ptype} { global POLY V set faces [lindex $POLY($ptype,I) 0] ;# How many faces for {set face 0} {$face < $faces} {incr face} { set xy [GetFaceXY $face] set color [lindex $POLY($ptype,$face) 3] .c create poly $xy -tag [list poly f$face] -fill $color -outline black .c bind f$face <1> {.c itemconfig current -fill $S(color)} } } proc DrawTabs {ptype} { global POLY S set faces [lindex $POLY($ptype,I) 0] ;# How many faces for {set face 0} {$face < $faces} {incr face} { set tabs [lindex $POLY($ptype,$face) 2] foreach tab $tabs { foreach {p0 p1} [GetSideXY $face $tab] break set v1 [RotateAdd $p1 $p0 120 $S(tabsize)] set v2 [RotateAdd $p0 $p1 -120 $S(tabsize)] set xy [concat $p0 $v1 $v2 $p1] .c create poly $xy -tag [list poly tab] -fill white -outline black } } .c lower tab } proc GetFaceXY {face} { global V set num [llength [array names V $face,*]] set xy {} for {set i 0} {$i < $num} {incr i} { set xy [concat $xy $V($face,$i)] } return $xy } proc GetSideXY {face n} { global V set n2 [expr {$n + 1}] if {! [info exists V($face,$n2)]} {set n2 0} return [list $V($face,$n) $V($face,$n2)] } # GetVertices -- populates V with all vertex info for every face proc GetVertices {type where face} { global S V polygon foreach {angle num} $polygon($type) break if {[llength $where] == 1} { ;# First polygon set V($face,0) {0 0} set V($face,1) [RotateC [list $S(len) 0] -$where] } else { ;# Polygon attached to another foreach {prev side} $where break foreach [list V($face,1) V($face,0)] [GetSideXY $prev $side] break } set p0 $V($face,0) set p1 $V($face,1) for {set i 2} {$i < $num} {incr i} { set V($face,$i) [RotateAdd $p0 $p1 $angle] set p0 $p1 set p1 $V($face,$i) } } proc CenterNet {} { global V set an [array names V] ;# All the vertices set a1 [lindex $an 0] ;# First vertex set x0 [set x1 [lindex $V($a1) 0]] ;# Initial min/max values set y0 [set y1 [lindex $V($a1) 1]] foreach a $an { foreach {x y} $V($a) break if {$x < $x0} {set x0 $x} elseif {$x > $x1} {set x1 $x} if {$y < $y0} {set y0 $y} elseif {$y > $y1} {set y1 $y} } set midx [expr {($x0 + $x1)/2}] ;# This should be the center set midy [expr {($y0 + $y1)/2}] foreach a $an { foreach {x y} $V($a) break set V($a) [list [expr {$x - $midx}] [expr {$y - $midy}]] } } proc GetVector {p0 p1 {sc 1}} { foreach {x0 y0} $p0 {x1 y1} $p1 break return [list [expr {$sc * ($x1-$x0)}] [expr {$sc * ($y1-$y0)}]] } proc AddVector {v0 v1} { foreach {x0 y0} $v0 {x1 y1} $v1 break return [list [expr {$x1+$x0}] [expr {$y1+$y0}]] } proc RotateAdd {p0 p1 angle {sc 1}} { set v [GetVector $p0 $p1 $sc] set v [RotateC $v $angle] return [AddVector $p1 $v] } # RotateC -- rotates vector v by beta degrees clockwise proc RotateC {v beta} { foreach {x y} $v break set beta [expr {$beta * atan(1) * 4 / 180.0}] set xx [expr {$x * cos($beta) - $y * sin($beta)}] set yy [expr {$x * sin($beta) + $y * cos($beta)}] return [list $xx $yy] } # ScaleIt -- scales everything to just fit on the canvas proc ScaleIt {} { set bbox [.c bbox poly] if {[llength $bbox] == 0} return foreach {x0 y0 x1 y1} [.c bbox poly] break foreach w [winfo width .c] h [winfo height .c] break set s [GetZoom $bbox $w $h 20] if {$s == 0} return .c scale poly 0 0 $s $s } proc GetZoom {bbox w h margin} { foreach {x0 y0 x1 y1} [.c bbox poly] break set pw [expr {$x1 - $x0}] set ph [expr {$y1 - $y0}] set sw [expr {double($w - $margin) / $pw}] set sh [expr {double($h - $margin) / $ph}] if {$sh < $sw} {set s $sh} else {set s $sw} return $s } proc NextPoly {{dir 1}} { global S set ptypes [GetPTypes] set len [llength $ptypes] set n [lsearch $ptypes $S(type)] set n [expr {($n + $dir) % $len}] set S(type) [lindex $ptypes $n] } proc PrintIt {{zoom 1}} { set height 1350 set width 975 set pageheight 9.0i set pagewidth 6.5i set fname [file join [pwd] polyhedron.ps] set bbox [.c bbox all] set zoom [GetZoom $bbox $width $height 0] set width [expr {$width / $zoom}] set height [expr {$height / $zoom}] foreach {x0 y0 x1 y1} $bbox break set x [expr {($x0 + $x1 - $width) / 2}] ;# Upper left corner set y [expr {($y0 + $y1 - $height) / 2}] set err [.c postscript -file $fname -rotate false -colormode color \ -x $x -y $y -width $width -height $height \ -pageheight $pageheight -pagewidth $pagewidth] if {$err == ""} { set msg "Created postscript version of the map in\n$fname" } else { set msg "Postscript creation error:\n$err" } tk_messageBox -title "Print" -message $msg } proc About {} { set msg "$::S(title)\nby Keith Vetter, March 2003\n\n" append msg "A polyhedron net is the planar unfolding of a polyhedron,\n" append msg "with each polygon represents a face of the polyhedron.\n" append msg "Included here are all five Platonic solids and several\n" append msg "of the thirteen Archimedean solids.\n\n" append msg "You can make a 3-D model of a polyhedron by printing\n" append msg "out a net, cutting it out, folding along the lines and\n" append msg "attaching the tabs. You can change the color of any\n" append msg "face by selecting a color and clicking on the polygon.\n\n" append msg "You cannot print directly from this program, but you can\n" append msg "create a color postscript version the net which you can\n" append msg "print using other tools." tk_messageBox -title "About $::S(title)" -message $msg } DoDisplay set S(type) [lindex [GetPTypes] [expr {int(rand() * [llength [GetPTypes]])}]]
can you please show the shapes not the scripts for them thank you... - customer
-- Just cut and paste the code, then run the command "DoDisplay"
KPV sorry, looks like the last few lines got lost. I've fixed that so it should work by cutting and pasting.
MG 23/11/04 Removed a stupid/rude edit made by a twink.
uniquename 2013jul29
This code could use an image to show what it produces:
(Thanks to 'gnome-screenshot', 'mtpaint', and ImageMagick 'convert' on Linux for, respectively, capturing the image to a PNG file, cropping the image, and converting the resulting PNG file to a JPEG file that was about 6 times smaller.)