This weekend I continued my experiments with Python and Avalon.  Before I was hosting Python in an existing app, but now I've started from almost scratch.  I have to clean up the code and wait for the outside world to get new Avalon bits, but I can describe a bit of Pythalon.

Basically it is a Python console below and a Avalon viewing area above.  I injected a variable called RootElement into the Python Processor so I can write little programs against the Avalon OM rooted in RootElement (hence the name).  It turns out to be way fun.  My first example is a little Koch snowflake generator.  I divided the code into two modules:  a platform independent pure math routine, and an Avalon dependent module that creates a Path.  Here's the first section:

from math import *

def vecadd(v1,v2):
       return [x+y for x,y in zip(v1,v2)]

def vecsub(v1, v2):
       return [x-y for x,y in zip(v1,v2)]

def scalarprod(s, v1):
       return [x * s for x in v1]

def dotprod(v1, v2):
       t = [x*y for x,y in zip(v1,v2)]
       s = 0.0
       for x in t:
           s += x
       return s
   
def length(vector):
       return sqrt(dotprod(vector,vector))

def vector(point1, point2):
       return [y - x for x,y in zip(point1, point2)]
       
def dist(point1, point2):
       return length(vector(point1, point2))

def normalize(vector):
       l = length(vector)
       return scalarprod(1.0/l, vector)


def KochFunc(point1, point2):
       if (len(point1) != 2):
              return []
       v = vector(point1,point2)
       n3 = scalarprod(1.0/3.0, v)
       c = cos(-pi/3)
       s = sin(-pi/3)
       n3rotated = [n3[0] * c - n3[1] * s, n3[0]* s + n3[1] * c]
       p1 = point1
       p2 = vecadd(point1, n3)
       p3 = vecadd(p2, n3rotated)
       p4 = vecadd(p2,n3)
       p5 = point2
       return [p1, p2, p3, p4, p5]
       
def KochFuncOnSequence(s):
       retval = []
       for i in range(len(s)-1):
              retval += KochFunc(s[i], s[i+1])[:4]
       retval += KochFunc(s[len(s)-1], s[0])
       return retval

and here's the second:

import sys
sys.LoadAssemblyByName("PresentationCore")
sys.LoadAssemblyByName("PresentationFramework")
sys.LoadAssemblyByName("WindowsBase")

from math import *
from System.Windows import *
from System.Windows.Media import *
from System.Windows.Controls import *
from System.Windows.Shapes import *
from Koch import *

def makePoints(sequence):
    retval = []
    for x in sequence:
        retval.append(Point(x[0],x[1]))
    return retval
 
def makeFigure(sequence):
    points = makePoints(sequence)
    figure = PathFigure()
    figure.StartAt(points[0])
    for x in points[1:-1]:
        figure.LineTo(x)
    return figure
 
def makeGeometry(sequence):
    g = PathGeometry()
    g.AddFigure(makeFigure(sequence))
    return g
 
def makeSnowFlake(sequence):
    g = makeGeometry(sequence)
    p = Path()
    p.Data = g
    return p

Scale = 800.0
StartTriangle = [[0,100], [Scale,100], [Scale/2, Scale*sin(pi/3)+100]]
FirstDegreeFlake = KochFuncOnSequence(StartTriangle)
SecondDegreeFlake = KochFuncOnSequence(FirstDegreeFlake)

def drawFlake(target, degree = 2, brush=Brushes.Cyan):
    s = StartTriangle
    for i in range(degree):
        s = KochFuncOnSequence(s)
    p = makeSnowFlake(s)
    p.Fill = brush
    p.SetValue(Canvas.TopProperty, 50.0)
    target.Children.Add(p)
    return p

def sampleFlake(target):
     stop1 = GradientStop(Colors.Yellow, 0.0)
     stop2 = GradientStop(Colors.Orange, 1.0)
     stops = GradientStopCollection()
     stops.Add(stop1)
     stops.Add(stop2)
     p = drawFlake(target, 6, LinearGradientBrush(stops))
     p.SetValue(Canvas.TopProperty, 120.0)
     p.Stroke = Brushes.Violet
     return p