Version 1 of Sun, moon, and stars

Updated 2002-09-06 07:23:32

Richard Suchenwirth - In the weekend fun project for Describing and rendering flags in Tcl, some geometrical shapes were required: sun (Taiwan style: 12 triangles arranged around a circle), moon (crescent), and stars. Since these involve quite some arithmetics on coordinates, the tasks were delegated to a separate geom package, whose procedures give and take coordinates, but don't know about canvases or colors.

A five-point star is described as a polygon of ten points: five are the corners of a regular pentagon, the others are the crossing points of every pair of lines between the pentagon edges. Maybe this code can be reused in other ways, too - feel free to grab it!

 namespace eval geom {
    variable p360 [expr atan(1.)*8/360]

    proc crosspoint {xa ya xb yb xc yc xd yd} {
        # compute crossing between two straight lines ("" if parallel)
        if {$xa==$xb} {
            set xres $xa ;# vertical - couldn't divide by deltax
        } else {
            set a [expr double($yb-$ya)/($xb-$xa)]
            set b [expr $yb-($a*$xb)]
        }
        if {$xc==$xd} {
            set xres $xc ;# vertical - couldn't divide by deltax
        } else {
            set c [expr double($yd-$yc)/($xd-$xc)]
            set d [expr $yd-($c*$xd)]
        }
        if {[info exists a] && [info exists c] && $a==$c} {return ""}
        if {![info exists a] && ![info exists c]} {return ""}
        if ![info exists xres] {
            set xres [expr double($d-$b)/($a-$c)]
        }
        if [info exists a] {
            set yres [expr $a*$xres+$b]
        } else {
            set yres [expr $c*$xres+$d]
        }
        list $xres $yres
    }

    proc star5 {x y r {skew 0}} {
        # compute coordinates for a five-point star
        variable p360
        foreach {p angle} {A 0 B 72 C 144 D 216 E 288} {
            set rad [expr ($angle-$skew)*$p360]
            set $p [list [expr $x+$r*sin($rad)] [expr $y-$r*cos($rad)]]
        }
        set F [eval crosspoint $A $C $B $E]
        set G [eval crosspoint $B $D $A $C]
        set H [eval crosspoint $C $E $B $D]
        set I [eval crosspoint $D $A $C $E]
        set J [eval crosspoint $E $B $A $D]
        concat $A $F $B $G $C $H $D $I $E $J
    }
    proc sunrays {x y r {n 12}} {
        # rotated triangles around a circle
        variable p360
        for {set i 0} {$i<$n} {incr i} {
            set rad [expr ($i*360./$n)*$p360]
            set rad1 [expr ($i*360./$n-170./$n)*$p360]
            set rad2 [expr ($i*360./$n+170./$n)*$p360]
            lappend res [list \
                [expr $x+$r*sin($rad)] [expr $y-$r*cos($rad)] \
                [expr $x+$r*0.67*sin($rad1)] [expr $y-$r*0.67*cos($rad1)] \
                [expr $x+$r*0.67*sin($rad2)] [expr $y-$r*0.67*cos($rad2)] \
            ]
        }
        set res
    }
 }

NB. This code contains no "moon". It is supposed to come here, but in the hurry I was in I put it directly into Describing and rendering flags in Tcl - it's just the superimposition of two circles anyway.


Here's a slicker routine for drawing a star (by [email protected] on c.l.t):

 proc MakeStar {x y delta} {
    set pi [expr {atan(1) * 4}]

    # Compute delta to inner corner
    set x1 [expr {$delta * cos(54 * $pi/180)}]
    set y1 [expr {$delta * sin(54 * $pi/180)}]
    set XY [expr {sqrt($x1*$x1 + $y1*$y1)}]
    set y2 [expr {$delta * sin(18 * $pi/180)}]
    set delta2 [expr {$XY * $y2 / $y1}]

    # Now get all coordinates of the 5 outer and 5 inner points
    for {set i 0} {$i < 10} {incr i} {
        set d [expr {($i % 2) == 0 ? $delta : $delta2}]
        set theta [expr {(90 + 36 * $i) * $pi / 180}]
        set x1 [expr {$x + $d * cos($theta)}]
        set y1 [expr {$y - $d * sin($theta)}]

        lappend coords $x1 $y1
    } 
    return $coords
 }

Arts and crafts of Tcl-Tk programming