0

I'm working on a school project around l-systems. I have a main.py that can convert an l-system to a drawing using pythonTurtle.

# Import libraries
import json
import turtle as tur
from datetime import datetime

# Getting input on what json file to use
def getFile():
    """
    Input: None
    ----------
    Output: Return file that is given by the user of the program
    """
    file = input("What is the name of the json file with the inputs?: ")
    f  = open(file) # Load in input file
    return f

# Get information of json file in dictionary
def getData(f):
    """
    Input: File
    ----------
    Output: Return a dictionary of the content of the given file 
    """
    data = json.load(f)
    f.close() # Close file after getting information in data
    return data

# Making variables in python with information from file
def getVariables(data):
    """
    Input: Dictionary with neede variables for an l-system
    ----------
    Output: Return the needed variables for an l-system
    """
    axiom = data['axiom']
    rules = data['rule']
    variables = data['variables']
    constants = data['constants']
    trans = data['trans']
    return axiom, rules, variables, constants, trans

# Apply the logic of an l-system
def lSystem(axiom, rules, iter):
    """
    Input: Axiom = string, rules = dictionary, iterations (iter) = int
    ----------
    Output: The resulting string after preforming the l-system with the inputs
    """
    new_string = ''
    old_string = axiom # Sart with the axiom

    for _ in range(iter):
        for string in old_string:
            if string in rules:
                new_string += rules[string] # Add the rule in the new_string
            else:
                new_string += string # When the el of the string is not in rules, just add the el in the new_string
        old_string = new_string
        new_string = ''

    return old_string

# Change the color of the drawing
def setColor(color, t):
    """
    Input: Color = string (with name of a color), t = a python turtle
    ----------
    Output: Python turtle with the given color
    """
    t.pencolor(color)
    return t

# Draw the given string by using the translations
def draw(string, trans):
    """
    Input: String (the end result of an l-system), translations (trans) = dictionary (the trans of the used l-system
    ----------
    Output: No return, will draw the given string by the given translations
    """
    screen = tur.getscreen() # Make new screen where the drawing will cmom
    t = tur.Turtle() # Initialize the turtle and give it the name "t"
    t.hideturtle()
    t.setheading(90) # Set starting position of turtle heading up

    stack = [] # Stack will be used to push and pop between positions

    for symbol in string:
        if symbol in trans: # Check if the el can get translated
            para = trans[symbol][1] # Para is the parameter that will be put in the used fuction
            if "draw" == trans[symbol][0]:
                t.forward(para) # Draw line with length para
            elif "angle" == trans[symbol][0]:
                t.left(para) # Rotate to the left with "para" degrees
            elif "forward" == trans[symbol][0]:
                # Move forward without drawing a line
                t.penup() # Raising pen
                t.forward(para) # Moving
                t.pendown() # Dropping pen, draw again
            elif "nop" == trans[symbol][0]:
                pass
            elif "push" == trans[symbol][0]:
                stack.append((t.pos(), t.heading())) # Add the current position and heading to stack
            elif "pop" == trans[symbol][0]:
                t.penup()
                t.setpos(stack[len(stack)-1][0]) # Set position and heading to last item in stack
                t.setheading(stack[len(stack)-1][1])
                t.pendown()
                stack.pop(len(stack)-1) # Remove last item from stack
            elif "color" == trans[symbol][0]:
                setColor(trans[symbol][1], t)

# Check if the input file has correct input data
def checkData(axiom, rules, alph, trans, pos_translations):
    """
    Input: All the variables of an l-system and the translations of the string that our program supports
        axiom = string, rules = dictionary, alph = list, trans = list, pos_translations = list (supported translations)
    ----------
    Output: Return False if the data is not the correct data to preform an l-system
    """
    if axiom == '': # We need an axiom to start the program
        return False

    if not isinstance(axiom, str): # Check if axiom is a string
        return False
    for symbol in axiom: # Check if every symbol in axiom is in the alphabet
        if not symbol in alph:
            return False

    if not isinstance(rules, dict): # Check if rules is a dictionary
        return False
    for rule in rules:
        if not rule in alph: # Rules is a dictionary, rule is a key
            return False
        for symbol in rules[rule]: # Symbol is every symbol in the value of the given key
            if symbol not in alph:
                return False
        if not isinstance(rule, str):
            return False
        if not isinstance(rules[rule], str):
            return False

    if not isinstance(alph, list): # Check if the alphabet is a list
        return False
    for symbol in alph: # Check if every symbol in the alphabet is a string
        if not isinstance(symbol, str):
            return False

    if not isinstance(trans, dict):
        return False
    for tran in trans: # Trans is a dictionary, tran is a key in trans
        if not tran in alph:
            return False
        if not isinstance(trans[tran] , list): # Trans[tran] is the value of the key 
            return False
        if not isinstance(trans[tran][0], str): # Trans[tran][1] is the second item in the value of the key, the value is a list
            return False
        if trans[tran][0] == "color": # When the function is color, we need a string not a value
            if not isinstance(trans[tran][1], str):
                return False
        else:
            if not isinstance(trans[tran][1], int):
                return False
        if not trans[tran][0] in pos_translations: # Check if the translation is supported by the program
            return False

# Check if input file contains needed variables
def checkFile(data):
    """
    Input: List (data of the input file)
    ----------
    Output: Return False if the needed variables are not in the input file
    """
    if not "axiom" in data:
        return False
    if not "rules" in data:
        return False
    if not "variables" in data:
        return False
    if not "constants" in data:
        return False
    if not "trans" in data:
        return False

    return True

# Write system history to file
def addHistory(axiom, rules, alph, trans, iterations, lstring, variables, constants):
    """
    Input: All variables that need to be stored in the history file
    ----------
    Output: Add a line with the variables to history.txt
    """
    f = open("history.txt","a")
    timestamp = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
    f.write(timestamp + "\t" + str(variables) + "\t" + str(constants) + "\t" + axiom + "\t" + str(rules) + "\t" + str(trans) + "\t" + str(iterations) + "\t" + str(lstring) + "\n") 

# Make alphabet variable
def makeAlph(variables, constants):
    """
    Input: Variables = list, constants = list
    ----------
    Output: List (The alphabet of the l-system = variables + constants)
    """
    alph = variables + constants
    return alph

# Main function
def main():

    file = getFile()

    # Get input on how many iterations the user wants to preform
    iter = int(input("How many iterations of the given l-system do you want to preform?: "))

    # Used_functions is a list of the possible translations that refer to a function
    # When you add more possible functions, add the translations of the function in the used_functions below
    used_functions = ("draw", "angle", "forward", "nop", "push", "pop", "color")

    data = getData(file)
    if checkFile(data) == False:
        print("The given input file is not contain the needed variabes.")
        return

    axiom, rules, variables, constants, trans = getVariables(data)
    alph = makeAlph(variables, constants)

    if checkData(axiom, rules, alph, trans, used_functions) == False:
        print("The given variables in the input file are not correct.")
        return

    lstring = lSystem(axiom, rules, iter)
    addHistory(axiom, rules, alph, trans, iter, lstring, variables, constants)
    print(lstring)
    draw(lstring, trans)
    tur.Screen().exitonclick() # Keep the drawing open unless you click on exit button

main()

This code can also be found on https://github.com/crearth/l-system To clear things up, we are working in linux. We need to make it possible for the user to use the command

python3 <python-main-file.py> --export my_image.eps

in the terminal. This command exports the drawing that was made to a file called my_image.eps. I have been looking for hours and cannot find a way to make this command possible. Can someone help me out with this? For example input files, you can look at https://github.com/crearth/l-system/tree/main/tests For more questions feel free to contact me.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mdaneels
  • 13
  • 4
  • It seems like you have a few questions. The first, being how to export the canvas to an `eps` file. That can be done with `t.getscreen().getcanvas().postscript(file="my_image.eps")` where `t` is your `t = tur.Turtle()`. [This](https://stackoverflow.com/a/13540724/12479639) is a pretty good example of how its used. The second is how to receive arguments from the command line. You can do that with `sys.argv` or the `argparse` module. – Axe319 Oct 29 '21 at 11:35
  • [`sys.argv`](https://docs.python.org/3/library/sys.html#sys.argv) docs. [`argparse`](https://docs.python.org/3/library/argparse.html?highlight=argparse#module-argparse) docs. – Axe319 Oct 29 '21 at 11:41
  • 1
    Found it, thanks! – mdaneels Oct 29 '21 at 15:26

0 Answers0