Files
computational-geometry-visu/algorithm.py
Pascal Lais 28097c2f2e
All checks were successful
continuous-integration/drone/push Build is passing
Fix algorithm.py and draw final result
2020-03-11 22:34:35 +01:00

194 lines
8.0 KiB
Python

#!/usr/bin/python3
"""The sweep module defines a base class sweep for various sweep algorithms. It also contains a
child-class for each individual algorithm."""
import copy
import linesegment
import point
class Algorithm():
"The Algorithm class is the base class for each individual algorithm"
def __init__(self):
self._input = None # The input values
self._result = {} # The result of the sweep
self._ready = False # If the algorithm is ready to be executed
self._running = False # If the algorithm is currently running
self._section = "start" # A string that names the current section of the algorithm
self._num_steps = {} # The number of steps that were needed to solve the problem
def start(self):
"""Start the performing the algorithm. Return True if it was successful"""
if not self._ready:
print("Error: Sweep is not yet ready to be performed")
return False
self._running = True
return True
def step(self):
"""Perform a single step of the algorithm."""
if self._section:
if self._section in self._num_steps:
self._num_steps[self._section] += 1
else:
self._num_steps[self._section] = 1
def run(self):
"""Execute the sweep. Returns the result dict."""
if not self.start():
return False
while self._running:
self.step()
return self._result
def is_running(self):
"""Return if the algorithm is running."""
return self._running
def get_result(self):
"""Return the result of the algorithm."""
return self._result
def draw(self, canvas, width, height, max_x, max_y):
"""Dummy for draw method"""
class NearestNeighborsSweep(Algorithm):
"""Calculate the pair of points inside a set, that have the minimal distance between each
other inside this set"""
def __init__(self, point_set=None):
super().__init__()
if isinstance(point_set, list):
for pnt in point_set:
if not isinstance(pnt, point.Point):
raise Exception(self, "Inputs have to be of type point.Point!")
self._input = copy.deepcopy(point_set)
self._ready = True
elif point_set is not None:
raise Exception(self, "Wrong input type for point_set")
self._sss = {} # The sweep state structure
self._es = [] # The event queue
self._result = {"success": False, \
"distance": None, \
"points": [None, None]}
def start(self):
"""Start the performing the algorithm. Return True if it was successful"""
if not super().start():
return False
self._result["success"] = False
self._sss = {"mindist": None, \
"points": []}
# Populate event structure
self._es = copy.deepcopy(self._input)
# Sort the input elements
self._num_steps["sort"] = point.sort_set(self._es)
return True
def step(self):
"""Perform a single step of the algorithm."""
if not self._running:
return
self._section = "sweep"
event = self._es.pop(0)
if self._sss["mindist"] is not None:
while len(self._sss["points"]) > 0 and \
self._sss["points"][0].get_x() <= (event.get_x() - self._sss["mindist"]):
del self._sss["points"][0]
for pnt in self._sss["points"]:
if self._sss["mindist"] is None:
self._sss["mindist"] = linesegment.LineSegment(pnt, event).get_length()
self._result["points"][0] = pnt
self._result["points"][1] = event
elif (event.get_y() - self._sss["mindist"]) < \
pnt.get_y() < (event.get_y() + self._sss["mindist"]):
distance = linesegment.LineSegment(pnt, event).get_length()
if self._sss["mindist"] > distance > 0:
self._sss["mindist"] = distance
self._result["points"][0] = pnt
self._result["points"][1] = event
super().step()
self._sss["points"].append(event)
if len(self._es) == 0:
self._result["success"] = True
self._result["distance"] = self._sss["mindist"]
self._running = False
def get_result_string(self, print_result=False):
"""Pack the result into a string."""
result_string = ""
if self._running:
result_string = "Sweep is still running."
elif not self._result["success"]:
result_string = "Sweep was not successful."
else:
result_string = "Sweep successfully completed\n"
result_string += " Summary:\n"
result_string += " Number of Inputs:" + str(len(self._input)) + "\n"
result_string += " Inputs: ["
for i, pnt in enumerate(self._input):
if i:
result_string += ","
result_string += str(pnt)
result_string += "]\n"
result_string += " Nearest Neighbors: "
result_string += str(linesegment.LineSegment(self._result["points"][0], \
self._result["points"][1]))
result_string += "\n"
result_string += " Distance: " + str(self._result["distance"]) + "\n"
result_string += " Number of steps:\n"
result_string += " Sort:" + str(self._num_steps["sort"]) +"\n"
result_string += " Sweep:" + str(self._num_steps["sweep"]) +"\n"
if print_result:
print(result_string)
return result_string
def draw(self, canvas, width, height, max_x, max_y):
"""Draw the algorithm state on a canvas"""
canvas.delete("all")
if self._running:
for pnt in self._input:
if len(self._es) > 0 and pnt == self._es[0]:
cur_x, cur_y = self._es[0].draw(canvas, width, height, max_x, max_y, "#0000FF")
canvas.create_line(cur_x, 0, cur_x, height, fill="#0000FF")
if self._sss["mindist"]:
canvas.create_line(cur_x - (self._sss["mindist"] * width / max_x), 0, \
cur_x - (self._sss["mindist"] * width / max_x), height, fill="#0000FF")
canvas.create_line(cur_x - (self._sss["mindist"] * width / max_x), \
cur_y - (self._sss["mindist"] * height / max_y), \
cur_x, cur_y - (self._sss["mindist"] * height / max_y), fill="#0000FF")
canvas.create_line(cur_x - (self._sss["mindist"] * width / max_x), \
cur_y + (self._sss["mindist"] * height / max_y), \
cur_x, cur_y + (self._sss["mindist"] * height / max_y), fill="#0000FF")
else:
canvas.create_line(0, 0, 0, max_y, fill="#0000FF")
if pnt in self._result["points"]:
pnt.draw(canvas, width, height, max_x, max_y, "#FF0000")
else:
pnt.draw(canvas, width, height, max_x, max_y)
if self._result["points"][0]:
linesegment.LineSegment( \
self._result["points"][0], self._result["points"][1] \
).draw(canvas, width, height, max_x, max_y, "#FF0000")
else:
for pnt in self._input:
if pnt in self._result["points"]:
pnt.draw(canvas, width, height, max_x, max_y, "#FF3333")
else:
pnt.draw(canvas, width, height, max_x, max_y, "#222222")
if self._result["points"][0]:
linesegment.LineSegment( \
self._result["points"][0], self._result["points"][1] \
).draw(canvas, width, height, max_x, max_y, "#FF0000")