Come è nata l'idea
Iniziando un corso di informatica, a scuola, in testa girava l'idea di creare un programma capace di creare dei grafi e mi piaceva il fatto di visualizzare su gui il cammino più breve tra due nodi usando l' Algoritmo di Dijkstra.
Fase di Sviluppo
Sono partito dell'idea di creare un programma molto simile al Software CAD con l'unica cosa che bisognava aggiungere qualche figura in più
quando si creano linee, meglio dire Archi.
Ogni Arco che si crea vengono creati due nodi, se premo su un nodo l'arco parte da quel nodo e finisce su un altro. Ogni arco ha il suo peso e di default viene calcolata la distanza cartesiana dal centro dei due nodi e viene divisa per 15, successivamente viene inserita in una casella di testo.
Premendo il tasto destro sull'Arco, viene aperto un piccolo menù in cui viene specificato:
Commento sul Codice
-
class Nodo:
-
def __init__(self, coords: list[tuple], n:int, line_id: int):
-
self.__coords = coords
-
self.__number = n
-
self.__line_id = line_id
-
-
def getCoords(self):
-
return self.__coords
-
-
def getNumber(self):
-
return self.__number
-
-
def getId(self):
-
return self.__line_id
Questo è come vede il programma i Nodi dei grafi. Composto da:
- class Arco:
- def __init__(self, coords: list[tuple], nodes: list[Nodo], height:int, line_id:int, bidirectional = False,**kargs):
- self.__coords = coords
- self.__nodes = nodes
- self.__height = height
- self.__line_id = line_id
- self.__bidirectional = bidirectional
- self.__kargs = kargs
- def getCoords(self):
- return self.__coords
- def getNodes(self):
- return self.__nodes
- def getHeight(self):
- return self.__height
- def getId(self):
- return self.__line_id
- def getBidirectional(self) -> bool:
- return self.__bidirectional
- def getKargs(self):
- return self.__kargs
- def getScheme(self, withHeight = True):
- s = ""
- s += " ".join([str(n.getNumber()) for n in self.__nodes])
- if withHeight:
- s += f" {self.__height}"
- if self.__bidirectional:
- s1 = s.split(" ")
- s1[0], s1[1] = s1[1], s1[0]
- s1 = " ".join(s1)
- s += f"\n{s1}"
- return s.strip()
- def getTotalInfo(self):
- s = self.__coords.copy()
- s.append({})
- if self.__bidirectional:
- s[-1]["BIDIREZIONALE"] = 1
- s[-1]["PESO"] = self.__height
- return s
- # ------------------------------------------ #
- def toggleBidirectional(self):
- self.__bidirectional = not self.__bidirectional
- def setBidirectional(self, value):
- self.__bidirectional = value
- def setHeight(self, value):
- self.__height = value
Questo è come vede il programma l'Arco, composto da:
- def logFunzione(func):
- def wrapper(*args):
- try:
- func(*args)
- except:
- err = traceback.format_exc()
- ora = time.strftime("%d-%m-%Y | %H:%M", time.localtime())
- messagebox.showerror("Notifica di Servizio", "Si è verificato un errore. Chiedere più informazioni al proprietario del software")
- with open("log.txt", "a") as file:
- file.write(f"[{ora}] =>{err}\n{'-'*130}\n")
- file.close()
- return wrapper
- # ------------------------------------------ #
- class GUI(ctk.CTk):
- ....
- @logFunzione
- def setPoint(self, event):
- ...
Per controllare gli eventuali errori che si verificano durante l'eseguzione del programma, senza riscrivere molto codice
ho introdotto un decoratore.
- self.archi += 1
- temp = self.temp_coods.copy()
- pm = [(temp[0][0] + temp[1][0])/2, (temp[0][1] + temp[1][1])/2]
- try: angle = math.degrees(math.atan2((temp[0][1] - temp[1][1]), (temp[0][0] - temp[1][0])))
- except: angle = 90
- lenght = math.sqrt((temp[0][0] - temp[1][0])**2 + (temp[0][1] - temp[1][1])**2)
- lenght /= 2
- lenght -= 10
- temp = list(map(lambda x: list(x), temp))
- temp[0][0] = lenght*cos(angle) + pm[0] # x
- temp[0][1] = lenght*sin(angle) + pm[1] # y
- temp[1][0] = lenght*cos(angle+180) + pm[0] # x
- temp[1][1] = lenght*sin(angle+180) + pm[1] # y
- line = self.canvas.create_line(temp, fill="white", arrow="last", arrowshape=(7.0, 11.0, 6.0), activewidth=3, width=2)
Per iniziare incremento il contatore degli archi self.archi += 1.
- if self.permitted_coods[0][0]:
- self.nodi += 1
- nodo1 = self.canvas.create_oval((x1,y1),(x2,y2), fill="#202123", outline="white", activewidth=2)
- text_nodo1 = self.canvas.create_text(self.temp_coods[0], text=str(self.nodi), activefill="red", fill="white", state="disabled")
- ogg_nodo1 = Nodo(self.temp_coods[0], self.nodi, nodo1)
- self.canvas.itemconfig(nodo1, tags=([pickle.dumps(ogg_nodo1)]))
- if event.num == 2:
- x,y = self.temp_coods[0]
- self.dict_nodes[f"{x} {y}"] = [(x,y), pickle.dumps(ogg_nodo1)]
- else:
- ogg_nodo1 = pickle.loads(self.permitted_coods[0][1])
self.permitted_coods è una matrice 2x2 in cui dice lo stato attuale nell'esatto punto in cui ho premuto, il primo elemento è un booleano
in cui mi dice se è uno spazio vuoto o meno, ciò lo determina usando i tags, se c'è una determianta condizione usando quel tag, sa se è uno spazio vuoto o meno.
Il secondo elemento è il tag stesso.