Code Sketch


Archimedes PI
By: Saurabh Kapoor
Category: Math
// Click the Run button in the toolbar above to start the story
//
// =================================================================
//
// Archimedes' estimation of PI
// 

val S = Staging
val unit = 100

def rads(degree: Double) = degree * Math.Pi / 180.0
val headerStyle = "text-align:center;font-size:110%;color:maroon;"

var page: StoryPage = _
var header: xml.Node = _

var pages = new collection.mutable.ListBuffer[StoryPage]

def pgHeader(hdr: String) =
    <p style={headerStyle}>
        {new xml.Unparsed(hdr)}
        <hr/>
    </p>


header = pgHeader("Archmedes' Pi")

page = Page(
    name = "Archimedes's estimation of Pi",
    body = 
        <body style="margin:15px;">
            <h1>Archimedes' estimation of Pi</h1>
            <p>
            We're going to explore the method Archimedes used for estimating the 
            value of <em>pi</em> represented by the symbol:
            {stFormula("""\pi""")}. 
            </p>
        </body>,
    code = {}
)

pages += page

def drawCircle(radius: Int)
{
    var side = (2 * Math.Pi * radius) / 360
    setPosition(-radius, 0)
    setPenColor(blue)
    setFillColor(green)
    setAnimationDelay(0)
    repeat(360)
    {
        forward(side)
        right(1)
    }
}


page = Page(
    name = "Pi - Definition",
    body = 
        <body style="margin:15px;">
            <h1>Definition of PI</h1>
            <p> PI is defined as the ratio of a circle's circumference to its diameter.
                See the circle on the right, whose radius can be controlled using the slider.
            </p>
        </body>,
    code = {
        clear()
        Mw.clear()
        Mw.hideAlgebraView()
        Mw.showAxes()
        Mw.variable("r", 4, 0, 10, 0.5, 50, 50)
        Mw.evaluate("Circle[(0, 0), r]")
    }
        //S.reset()
        //S.fill(green)
        //S.circle(S.O, unit)
        //S.setFillColor(green)
        //S.setPenColor(blue)
        //S.line(-unit, 0, unit, 0)
        //S.text("diameter", -20, 20)
        // drawCircle(unit)
)

pages += page

//  A method to return the points of a regular polygon of N points
//  inscribed in the circle with the supplied radius
// center: The center of the circle
// radius: The radius of the circle in which we want to inscribe the polygon
// nSides: The number of sides of the polygon
// initialAngle: The angle by which we want to rotate the polygon counter-clockwise
def getPolygonPoints(center: Point, 
                     radius: Double, 
                     nSides: Int,
                     initialAngle: Double) : List[Point] = 
{
    // We will first generate the inital set of points on a circle with radius 100, along origin 0,0
    // with an initalAngle of (0,0).
    // Once we have those points, we will transform according to the args
    
    var initialPt = new Point(0, radius)
    
    def createPoint(count: Int) : Point = {
        var theta = rads(360.0/nSides * count + initialAngle);
        var cosTheta = Math.cos(theta)
        var sinTheta = Math.sin(theta)
        var newX = initialPt.x * cosTheta - initialPt.y * sinTheta
        var newY = initialPt.x * sinTheta + initialPt.y * cosTheta 
        new Point(newX + center.x, newY + center.y)
    }
    
    for(i <- List.range(0, nSides)) yield createPoint(i)
}

// Draw the inner and outer polygons and trap a circle within them
def drawCircleAndPoly(radius: Double, nSides: Int) = 
{
    val initialAngle = 180.0 / nSides
    val radiusOuter = radius / Math.cos(rads(initialAngle))
    gridOff()
    axesOff()

    val innerPerimeter = Math.sin(rads(initialAngle)) * nSides
    val outerPerimeter = Math.tan(rads(initialAngle)) * nSides
    
    S.text("%1.10f < pi < %1.10f" format(innerPerimeter, outerPerimeter), -110, 160)
    S.text("pi ~ %1.10f" format((innerPerimeter + outerPerimeter)/2), -110, 140)
    val innerPoly = getPolygonPoints(S.O, radius, nSides, 0)
    val outerPoly = getPolygonPoints(S.O, radiusOuter, nSides, initialAngle)

    // Mark the origin
    S.dot(S.O)

    // Now draw the outer polygon
    S.setPenColor(blue)
    S.setFillColor(yellow)
    S.polygon(outerPoly)

    // Draw the circle
    S.setPenColor(green)
    S.setFillColor(new Color(255, 0, 255))
    S.circle(S.O, radius)

    // Draw the inner polygon
    S.setPenColor(red)
    S.setFillColor(new Color(255, 255, 255))
    S.polygon(innerPoly)
}

page = Page(
    name = "Polygons - inscribed and circumscribed",
    body =
        <body>
            <h1>Trapping the circle</h1>
            <p>The circle is inscribed and circumscribed by a regular Pentagon (5 sided polygon).</p>
            <p>Try changing the number of sides below to see how the circle gets 
                <em>trapped</em> by the two Polygons </p>
        </body>,
    code = {
        drawCircleAndPoly(100, 5)
        stAddField("Sides", 5)
        stAddButton ("Make Polygons") {
            val size = stFieldValue("Sides", 5)
            S.reset()
            drawCircleAndPoly(100, size)
        }
    }
)

pages += page

val story = Story(pages: _*)

stClear()
stPlayStory(story)