diff --git a/algorithm.py b/algorithm.py index fb78445..17d2cea 100644 --- a/algorithm.py +++ b/algorithm.py @@ -191,3 +191,111 @@ class NearestNeighborsSweep(Algorithm): self._result["points"][0], self._result["points"][1] \ ).draw(canvas, width, height, max_x, max_y, "#FF0000") +class ConvexHull(Algorithm): + + """This algorithm calculates the convex hull for a set of points""" + + 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, \ + "lt": [], \ + "lb": [], \ + "rt": [], \ + "rb": [], \ + "hull": []} + 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 = {"max": None, \ + "min": None} + # Populate event structure + self._es = copy.deepcopy(self._input) + # Sort the input elements + self._num_steps["sort"] = point.sort_set(self._es) + self._section = "sweep-left-to-right" + return True + def step(self): + """Perform a single step of the algorithm.""" + if not self._running: + return + + if self._section == "sweep-left-to-right": + event = self._es.pop(0) + if self._sss["min"] is None or self._sss["max"] is None: + self._sss["min"] = event + self._sss["max"] = event + elif event.get_y() < self._sss["min"].get_y(): + self._result["rb"].append(linesegment.LineSegment(self._sss["min"], event)) + self._sss["min"] = event + elif event.get_y() > self._sss["max"].get_y(): + self._result["rt"].append(linesegment.LineSegment(self._sss["max"], event)) + self._sss["max"] = event + + super().step() + if len(self._es) == 0: + self._sss["min"] = None + self._sss["max"] = None + self._es = copy.deepcopy(self._input).reverse() + self._section = "sweep-right-to-left" + + elif self._section == "sweep-right-to-left": + event = self._es.pop(0) + if self._sss["min"] is None or self._sss["max"] is None: + self._sss["min"] = event + self._sss["max"] = event + elif event.get_y() < self._sss["min"].get_y(): + self._result["rb"].append(linesegment.LineSegment(self._sss["min"], event)) + self._sss["min"] = event + elif event.get_y() > self._sss["max"].get_y(): + self._result["rt"].append(linesegment.LineSegment(self._sss["max"], event)) + self._sss["max"] = event + + super().step() + if len(self._es) == 0: + self._section = "sweep-left-to-top" + + elif self._section == "sweep-left-to-top": + event = self._es.pop(0) + if len(self._es) == 0: + self._section = "sweep-left-to-bottom" + + elif self._section == "sweep-left-to-bottom": + event = self._es.pop(0) + if len(self._es) == 0: + self._section = "sweep-right-to-top" + + elif self._section == "sweep-right-to-top": + event = self._es.pop(0) + if len(self._es) == 0: + self._section = "sweep-right-to-bottom" + + elif self._section == "sweep-right-to-bottom": + event = self._es.pop(0) + if len(self._es) == 0: + self._section = "report-hull" + elif self._section == "report-hull": + for line in self._result["lb"]: + self._result["hull"].append(line) + for line in self._result["rb"].reverse(): + self._result["hull"].append(line) + for line in self._result["rt"]: + self._result["hull"].append(line) + for line in self._result["lt"].reverse(): + self._result["hull"].append(line) + self._result["success"] = True + self._running = False + +