## VSFX 705 - Programming Concept
##
## Sampler Quilt v1.0
##
## Ziye Liu
##
## Input:
## Number of how many quilt blocks in each row and column,
## and the size of the quilt.
##
## Output:
## A Sampler Quilt!
##
## Quilt blocks are assign from a pattern library which
## contains 5 different quilt patterns, and the color is
## from a library that has 6 different color sets.
##
###################################################################### 


import turtle
import math

##set turtle to "fast"(0) speed
turtle.speed(0)

## Set Window Title:
turtle.title("Sampler Quilt, v1.0, by Ziye Liu, 2013")

## Color Set:
colorList1 = ["#4D5558", "#F2E3B6", "#FFDF85", "#F29966", "#D95252"]
colorList2 = ["#F2F2F2", "#C6E070", "#91C46C", "#287D7D", "#1C344C"]
colorList3 = ["#F2F2E9", "#D9D7C5", "#A69580", "#736766", "#734854"]
colorList4 = ["#FDEDD0", "#BCF1ED", "#FF634D", "#FD795B", "#FFF0AA"]
colorList5 = ["#655499", "#6093BF", "#68D4D4", "#56BF95", "#17996B"]
colorList6 = ["#48474A", "#5F5266", "#99718B", "#CF8998", "#FFADBF"]
## Put the colorlist into another list, so that they can be assign to patterns:
colorSet = [colorList1, colorList2, colorList3, colorList4, colorList5, colorList6]

##Visual Settings
##Ask the user how many quilt blocks they want:
eachLineNum = input ("Q(1/3): How many quilt blocks in a row you want? (eg. 5): ")
rowNum = input ("Q(2/3): How many rows do you want? (eg. 5): ")
quiltWidth = input ("Q(3/3): The horizonal size of the quilt, in pixel (eg. 800): ")
print "..."
print "...Okay, I'll make a",eachLineNum,"by",rowNum,"sampler quilt."
print "...it'll be",quiltWidth,"px in width."
print "...Working..."

##turtle's drawing line width and line color:
glbLineWidth = 2
glbPenColor = ("#333333")
turtle.color(glbPenColor)
turtle.width(glbLineWidth)

##Viarables:
beginPos = turtle.pos()
colorCount = 6 ## don't change this, defines how many color sets in this program
patternCount = 5 ## don't change this, defines how many quilt patterns in this program
glbBlockLength = quiltWidth / eachLineNum ## Length of each single block, based on users input
gap = glbBlockLength/30 ## Gap between each single block
quiltFrameWidth = gap * 5 ## The width of the outside frame of the sampler quilt
##set the background size of the quilt block area:
quiltBGWidth = glbBlockLength * eachLineNum + gap * ( eachLineNum - 1)
quiltBGHeight = glbBlockLength * rowNum + gap * ( rowNum - 1)

##set turtles initial position:
turtle.penup()
turtle.setpos(-(glbBlockLength*eachLineNum+gap*eachLineNum+quiltFrameWidth*2)/2,(glbBlockLength*rowNum+gap*rowNum+quiltFrameWidth*2)/2)
turtle.pendown()

##set window size to adapt the quilt size
turtle.setup(((glbBlockLength+gap)*eachLineNum+quiltFrameWidth*2)*1.2, ((glbBlockLength+gap)*rowNum+quiltFrameWidth*2)*1.2)



######################################################################
######################################################################
################################ FUNCTIONs ###########################
######################################################################
######################################################################

##
## Draw a single Quilt Block Square, base on the global variable
def drawBlockSq():
    for i in range (0,4):
        turtle.forward(glbBlockLength)
        turtle.right(90)
        
## Draw a block that's 1/4 size of the current quilt block
def drawHalfBlock(color):
    turtle.begin_fill ()
    turtle.fillcolor(color)
    drawSquare(glbBlockLength/2)
    turtle.end_fill ()
    
## Draw a square, usually used in quilt patterns
def drawSquare(length):
    for i in range (0,4):
        turtle.forward(length)
        turtle.right(90)

## Go to the center of the current quilt block
def gotoBlockCenter(degree, halfsize):
    turtle.penup()
    turtle.forward(glbBlockLength/halfsize)
    turtle.right(90*degree)
    turtle.forward(glbBlockLength/halfsize)
    turtle.pendown()

## Go to the next quilt block on the right
def moveRightHalfBlock():
    turtle.penup()
    turtle.seth(0)
    turtle.forward(glbBlockLength/2)
    turtle.pendown()

## Return to the beginning position, get ready for the next step
def gotoBeginPos():
    turtle.penup()
    turtle.goto(beginPos)
    turtle.seth(0)
    turtle.pendown()
## Move the turtle
def moveit(position):
    turtle.penup()
    turtle.goto(position)
    turtle.pendown()

## Move the turtle, based on the length of each block
def moveDivide(divide):
    turtle.penup()
    turtle.forward(glbBlockLength/divide)
    turtle.pendown()
    
#########################################################################
#########################################################################
############################# PATTERN Library ###########################
#########################################################################
#########################################################################
    

############################ No.1 Winding Ways ##########################

    
## Five color input, will be choose from the color library
def windingWays(color1, color2, color3, color4, color5):
    currentPos = turtle.pos() # remember the turtle's beginning position
    turtle.write("Winding Ways") # write the pattern's name on screen
    drawBlockSq() # Draw the basic block
    arcRepeat = 3 # Define how many time the sub block repeats
    
    ## A single piece of the Arc Shape
    def drawArcPiece(color):
        turtle.begin_fill ()
        turtle.fillcolor(color)
        turtle.circle(glbBlockLength/arcRepeat, 360/12)
        turtle.right(360/6)
        turtle.circle(glbBlockLength/arcRepeat, -(360/12))
        turtle.right(360/6)
        turtle.circle(glbBlockLength/arcRepeat, 360/12)
        turtle.end_fill ()

    ## A block of the arc shape
    def drawArcBlock(color):
        for i in range(0,2):
            drawArcPiece(color)
            turtle.right(90)
            drawArcPiece(color)
        gotoBlockCenter(-1,4)

    ## Draw a sub block, based on the number of repetition
    def drawSubBlock(color):
        turtle.seth(0)
        turtle.begin_fill()
        turtle.fillcolor(color)
        drawSquare(glbBlockLength/arcRepeat)
        turtle.end_fill()

    ## Go to the sub block's center, prepare for the arc shape
    def gotoSubBlockCenter():
        turtle.penup()
        turtle.forward(glbBlockLength/arcRepeat/2)
        turtle.right(90)
        turtle.forward(glbBlockLength/arcRepeat/2)
        turtle.pendown()
        
##    OLD VERSION ALGORITHM
##    #1
##    drawHalfBlock(color1)
##    gotoBlockCenter(1,4)
##    drawArcBlock(color2)
##    
##    moveRightHalfBlock()
##
##    #2
##    drawHalfBlock(color2)
##    gotoBlockCenter(1,4)
##    drawArcBlock(color1)
##
##    turtle.penup()
##    turtle.seth(0)
##    turtle.backward(glbBlockLength/2)
##    turtle.right(90)
##    turtle.forward(glbBlockLength/2)
##    turtle.right(-90)
##    turtle.pendown()
##
##    #3
##    drawHalfBlock(color2)
##    gotoBlockCenter(1,4)
##    drawArcBlock(color1)
##
##    moveRightHalfBlock()
##
##    #4
##    drawHalfBlock(color1)
##    gotoBlockCenter(1,4)
##    drawArcBlock(color2)
##




##    New Version Algorithm, can control the repetition number
##    and assign color using modulus
    currentColorList = [color1, color2]
    for j in range(0,arcRepeat):
        moveit(currentPos)
        y = turtle.ycor()
        for i in range(0,arcRepeat):
            x = turtle.xcor()
            turtle.pu()
            turtle.goto(x + i * glbBlockLength/arcRepeat, y - j * glbBlockLength/arcRepeat)
            turtle.pd()
            turtle.seth(0)
            drawSubBlock(currentColorList[0 + (i+j+1) % 2])
            gotoSubBlockCenter()
            drawArcBlock(currentColorList[0 + (i+j) % 2])
            moveit(currentPos)
        turtle.seth(0)
    
    #reset position
    gotoBeginPos()

############################## No.2 Blazing Star# ##########################

## the basic diamond shape
def drawDiamond(diamondSide,fromCenter,clockwise):
    beginHeading = turtle.heading()
    cCenterPos = turtle.pos()
    turtle.penup()
    turtle.forward(diamondSide*fromCenter)
    turtle.pendown()
    turtle.forward(diamondSide)
    turtle.right(45*clockwise)
    turtle.forward(diamondSide)
    turtle.right(135*clockwise)
    turtle.forward(diamondSide)
    turtle.right(45*clockwise)
    turtle.forward(diamondSide)
    turtle.right(-45*clockwise)
    turtle.penup()
##    turtle.forward(diamondSide*fromCenter)
    turtle.goto(cCenterPos)
    turtle.pendown()
    turtle.seth(beginHeading)
    
def blazingStar(color1, color2, color3, color4, color5):
    beginPos = turtle.pos()
    turtle.write("Blazing Star")
    turtle.begin_fill()
    turtle.fillcolor(color1)
    drawBlockSq()
    turtle.end_fill()

    gotoBlockCenter(1,2)
    ## define the side length of each diamond shape
    diamondSide = glbBlockLength/2/(1+1+1+math.sqrt(2)/2)


    #1st layer
    for i in range(0,8):
        turtle.begin_fill()
        turtle.fillcolor(color2)
        drawDiamond(diamondSide, 0, 1)
        turtle.right(45)
        turtle.end_fill()

    #2nd layer clockwise
    for i in range(0,8):
        turtle.begin_fill()
        turtle.fillcolor(color3)
        drawDiamond(diamondSide, 1, 1)
        turtle.right(45)
        turtle.end_fill()
    #2nd layer counter clockwise
    for i in range(0,8):
        turtle.begin_fill()
        turtle.fillcolor(color3)
        drawDiamond(diamondSide, 1, -1)
        turtle.right(45)
        turtle.end_fill()

    #3rd layer clockwise
    for i in range(0,8):
        turtle.begin_fill()
        turtle.fillcolor(color4)
        drawDiamond(diamondSide, 2, 1)
        turtle.right(45)
        turtle.end_fill()
    #3rd layer counter clockwise
    for i in range(0,8):
        turtle.begin_fill()
        turtle.fillcolor(color4)
        drawDiamond(diamondSide, 2, -1)
        turtle.right(45)
        turtle.end_fill()
    #3rd layer middle
    ## use this offset function to draw the diamond shape into it's position
    def offsetMid(a,b):
        turtle.penup()
        turtle.forward(diamondSide*a)
        turtle.right(45)
        turtle.forward(diamondSide*b)
        turtle.left(45)
        turtle.pendown()
    for i in range(0,8):
        cCenterPos = turtle.pos()
        offsetMid(-1,1)
        turtle.begin_fill()
        turtle.fillcolor(color4)
        drawDiamond(diamondSide, 2, 1)
        turtle.end_fill()
        turtle.penup()
        turtle.goto(cCenterPos)
        turtle.pendown()
        turtle.right(45)


    #reset position
    gotoBeginPos()


################################ No.3 Log Cabin ############################

beginPos = turtle.pos()
frameW = glbBlockLength/(4*2+1)
frameH = glbBlockLength - frameW
dashGap = frameW/6                          # dash line's gap
dashLength = frameW/3                       # dash line's length
def drawOneframe(fn):                       # define the function for 1 frame
    for i in range(0,2):
        turtle.forward(frameW)              # width
        turtle.right(90)
        turtle.forward(frameH-fn*frameW*2)  # height
        turtle.right(90)
def drawDashFrame(fn):                      # draw  dash line inside the frame
    turtle.pencolor("#EEEEEE")              # override turtle's line color
    turtle.width(1)                         # override turtle's line width to 1
    # go to inside of the frame:
    turtle.penup()
    for i in range (0,2):
        turtle.right( 90 * ( 1 - i * 2 ) )
        turtle.forward(dashGap)   
    turtle.pendown()
    # draw the dash line rectangle:
    for i in range (0,2):
        dashline((frameW-dashGap*2), dashLength) # width
        turtle.right(90)
        dashline((frameH-fn*frameW*2-dashGap*2), dashLength) # height
        turtle.right(90)
    turtle.width(glbLineWidth)              #reset turtle's line width
    # go back to the frame's original position
    turtle.penup()
    for i in range (0,2):
        turtle.left( 90 * ( 1 - i * 2 ) )
        turtle.forward( dashGap * ( 1 - i * 2 ) )
    turtle.pendown()
    turtle.pencolor(glbPenColor)            #reset turtle's line color
    
def moveToNextFrame(fn):
    turtle.penup()
    turtle.forward(glbBlockLength-fn*frameW*2)
    turtle.pendown()
    turtle.right(90)

def moveToNextLayer():
    turtle.penup()
    for i in range (0,2):
        turtle.forward(frameW)
        turtle.right( 90 * ( 1 - i * 2 ) )
    turtle.pendown()

## draw the log cabin
def logCabin(color1, color2, color3, color4, color5):
    beginPos = turtle.pos()
    frameColors = [color5, color4, color3, color2, color1]
    turtle.write("Log Cabin")
    turtle.begin_fill()
    turtle.fillcolor(color1)
    drawBlockSq()
    turtle.end_fill()

    for i in range (0,4):
        for b in range (0,4):
            turtle.begin_fill()
            turtle.fillcolor(frameColors[i])
            drawOneframe(i)
            turtle.end_fill()
            drawDashFrame(i)
            moveToNextFrame(i)
        moveToNextLayer()
   
           
    #reset position
    gotoBeginPos()
    


########################## No.4 Marinerd's Compass #######################
##
## defines the radius of the compass shape
compassR = glbBlockLength / 2 * ( 14.0 / 15.0 )

def drawHalfDiamond(mirror): # draw half of the dimond shape
    ''' mirror: 1 = normal shape, -1 = flip horizonal shape
    '''
    turtle.forward(compassR)
    turtle.right((180-15)*mirror)
    turtle.forward(compassR * math.sin(math.radians(45)) / math.sin(math.radians(120)))
    turtle.right((180-(180-45-15))*mirror)
    turtle.forward(compassR * math.sin(math.radians(15)) / math.sin(math.radians(120)))
    turtle.right((180-60+15)*mirror)

def Compass(color1, color2, color3, color4, color5):
    beginPos = turtle.pos()
    frameColor = [color1, color2, color3, color4, color5]
##    print "begin pos = ", beginPos
    turtle.write("Marinerd's Compass")
    turtle.begin_fill()
    turtle.fillcolor(color1)
    drawBlockSq()
    turtle.end_fill()

    gotoBlockCenter(1,2)

    turtle.penup()
    turtle.forward(compassR)
    turtle.left(90)
    turtle.pendown()

    ##draw the circle
    turtle.begin_fill()
    turtle.fillcolor(color2)
    turtle.circle(compassR)
    turtle.end_fill()

    moveit(beginPos)

    gotoBlockCenter(1,2)

    turtle.right(22.5)
    ##draw the compass shape
    for k in range(0,2):
        for j in range(0,2):
            for i in range(0,4): ## draw one layer
                turtle.begin_fill()
                turtle.fillcolor(frameColor[3])
                drawHalfDiamond(1)
                turtle.end_fill()
                
                turtle.begin_fill()
                turtle.fillcolor(frameColor[4])
                drawHalfDiamond(-1)
                turtle.end_fill()
                
                turtle.right(90)
##                print turtle.pos()
            turtle.right(45)
        turtle.right(22.5)    
    
    #reset position
    gotoBeginPos()

############################## No.5 Storm at Sea #############################
## the square element in the corner
def drawTriSq(sqLength, color1, color2, color3, color4, color5):
    beginPos = turtle.pos()
    
    turtle.begin_fill()
    turtle.fillcolor(color3)
    drawSquare(sqLength)
    turtle.end_fill()
    
    turtle.penup()
    turtle.forward( sqLength/2 )
    turtle.pendown()

    turtle.right(45)

    turtle.begin_fill()
    turtle.fillcolor(color1)
    drawSquare( sqLength / 2 * math.sqrt(2) )
    turtle.end_fill()
    
    turtle.penup()
    turtle.forward( sqLength / 2 * math.sqrt(2) / 2)
    turtle.pendown()
    
    turtle.right(45)

    turtle.begin_fill()
    turtle.fillcolor(color5)
    drawSquare( sqLength/2 )
    turtle.end_fill()

    moveit(beginPos)
    turtle.right(-90)




def stormAtSea(color1, color2, color3, color4, color5):
    beginPos = turtle.pos()

    def drawMidRect():
        ##goto center block begin position
        moveDivide(4)

        ##mid rectangle
        listPos = []    
        turtle.begin_fill()
        turtle.fillcolor(color2)
        for i in range(0,4):
            sideN = i % 2 + 1
            ##print sideN
            turtle.forward(glbBlockLength/(4*sideN)) # width
            listPos.append(turtle.pos())
            ##print "listPos:", listPos
            turtle.forward(glbBlockLength/(4*sideN)) # height
            turtle.right(90)    
        turtle.end_fill()

        ##diamond in mid rectangle
        moveit(listPos[0])  
        turtle.begin_fill()
        turtle.fillcolor(color4)
        for i in range(0,5):
            turtle.goto(listPos[i%4])
        turtle.end_fill()

        #to next pos
        moveDivide(2)
        turtle.right(90)
    
    turtle.write("Storm at Sea")
    drawBlockSq()

    ##corner squares
    for i in range(0,4):
        drawTriSq(glbBlockLength/2/2, color1, color2, color3, color4, color5)
        moveDivide(1)
        turtle.right(90)
    ##mid square       
    moveDivide(4)
    turtle.right(90)
    moveDivide(4)
    turtle.right(-90)
    drawTriSq(glbBlockLength/2, color1, color2, color3, color4, color5)

    

    moveit(beginPos)
    for i in range(0,4):
        drawMidRect()




###################### Pattern Library Ends here #######################
########################################################################
########################################################################


##
##Define Basic Pattern Block Funtion ( for one Line )
##Draw one pattern from the pattern list, based on the "n" parameter
def drawBasicBlock(n, color1, color2, color3, color4, color5):
    if n == 1:
        windingWays(color1, color2, color3, color4, color5)
    if n == 2:
        blazingStar(color1, color2, color3, color4, color5)
    if n == 3:
        logCabin(color1, color2, color3, color4, color5)
    if n == 4:
        Compass(color1, color2, color3, color4, color5)
    if n == 5:
        stormAtSea(color1, color2, color3, color4, color5)
           
##
##Define Fuction : Move turtle to the next position            
def nextPos():
    ## saved position + offset
    turtle.penup()
    turtle.goto(currentPos)
    turtle.seth(0)
    turtle.forward(glbBlockLength+gap)
    turtle.pendown()

##
## Dashed Line Function
def dashline (length, dashLength):
    beginPos = turtle.pos()
    
    ##the remain length of the whole dash line:
    remainlength = length
    
    ##set the step number needs to draw the dash line:
    for dashStep in range (0, (length - length % dashLength)/dashLength/2+1):
##        print "Dash Step:", dashStep
        
        ##draw the dash line
        if remainlength >= dashLength * 2:
            turtle.pendown()
            turtle.forward(dashLength)
            turtle.penup()
            turtle.forward(dashLength)
            ##update the remainlength
            remainlength = remainlength - dashLength * 2

        ##draw the last step, based on the remain length        
        elif remainlength < dashLength *2:
            turtle.pendown()
            turtle.forward(remainlength)


############################ FUNCTIONS End here ##########################
##########################################################################
##########################################################################


## draw the backplate
def drawQuiltBG(color):
    turtle.begin_fill()
    turtle.fillcolor(color)    
    for i in range(0,2):
        turtle.forward(quiltBGWidth)
        turtle.right(90)
        turtle.forward(quiltBGHeight)
        turtle.right(90)
    turtle.end_fill()
## draw the quilt frame
def drawQuiltFrame(color):
    turtle.seth(0)
    turtle.begin_fill()
    turtle.fillcolor(color)
    for i in range(0,2):
        turtle.forward(quiltBGWidth + quiltFrameWidth * 2)
        turtle.right(90)
        turtle.forward(quiltBGHeight + quiltFrameWidth * 2)
        turtle.right(90)
    turtle.end_fill()

drawQuiltFrame(colorList2[3])
turtle.penup()
turtle.forward(quiltFrameWidth)
turtle.right(90)
turtle.forward(quiltFrameWidth)
turtle.right(-90)
turtle.pendown()
drawQuiltBG(colorList2[0])

##
##
## draw the sampler quilt
##
##
for j in range(0, rowNum):
    row = j % rowNum
    print "row:",row
    for i in range(0,eachLineNum):
        num = (i - row) % patternCount # 5 blocks
        #i + j
        ccolorN = (i + j) % colorCount # 6 color sets
        currentPos = turtle.pos()
        colorChoice = colorSet[(ccolorN)] # pick color from color set
        print "i=", i, "pattern#", num+1, "colorchoice", ccolorN
##        print colorChoice
        #num+1
        drawBasicBlock(num+1, colorChoice[0], colorChoice[1], colorChoice[2], colorChoice[3], colorChoice[4])
        nextPos()
    turtle.penup()
    turtle.backward((glbBlockLength+gap)*eachLineNum)
    turtle.right(90)
    turtle.forward(glbBlockLength+gap)
    turtle.right(-90)
    turtle.pendown()
        
print "..."
print "YEAH! It's done!"
turtle.exitonclick ()








##colorChoice = colorList3
##print "current color set", colorChoice
##drawBasicBlock(1, coorChoice[0], colorChoice[1], colorChoice[2], colorChoice[3], colorChoice[4])







## Old version algorithm for the pattern layout:
################################################
##Generate the pattern numbers for line1
##
##line1 = []
##
##
##for line1number in range (1,eachLineNum+1):
##    line1.append(line1number)
##
##for i in range (1,eachLineNum+1):
##    line1.insert(0,line1.pop())


##list1 = []
##quiltRows = 3
##quiltColumns = 6
##first line
##for i in range(0,5):
##    list1.append(i)
##all lines
##for a in range(0,7): # how many lines
##    print "begin" #set begin position at the current line
##    for i in range(0,100):
##        if i < 5:
##            print list1[i]
##        elif i >=5:
##            print list1[i-30]
##    print "end" #fuction move next to next line
##    list1.insert(0,list1.pop())
