From fd3d055115b5257f87215f75c72f88f8f4cfb291 Mon Sep 17 00:00:00 2001 From: Pascal Lais Date: Fri, 20 Mar 2020 12:06:10 +0100 Subject: [PATCH] Add missing parts of ConvexHullIncremental The algorithm parts to clean up the four parts of the convex hull were not implemented yet. Also added draw function for completed algorithm. --- algorithm.py | 124 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 18 deletions(-) diff --git a/algorithm.py b/algorithm.py index 17d2cea..e3115a0 100644 --- a/algorithm.py +++ b/algorithm.py @@ -191,7 +191,7 @@ class NearestNeighborsSweep(Algorithm): self._result["points"][0], self._result["points"][1] \ ).draw(canvas, width, height, max_x, max_y, "#FF0000") -class ConvexHull(Algorithm): +class ConvexHullIncremental(Algorithm): """This algorithm calculates the convex hull for a set of points""" @@ -220,7 +220,11 @@ class ConvexHull(Algorithm): self._result["success"] = False self._sss = {"max": None, \ - "min": None} + "min": None, \ + "lt": [], \ + "lb": [], \ + "rt": [], \ + "rb": []} # Populate event structure self._es = copy.deepcopy(self._input) # Sort the input elements @@ -236,66 +240,150 @@ class ConvexHull(Algorithm): event = self._es.pop(0) if self._sss["min"] is None or self._sss["max"] is None: self._sss["min"] = event + self._result["lb"].append(event) self._sss["max"] = event + self._result["lt"].append(event) elif event.get_y() < self._sss["min"].get_y(): - self._result["rb"].append(linesegment.LineSegment(self._sss["min"], event)) + self._result["lb"].append(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._result["lt"].append(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._es = copy.deepcopy(self._input) + self._num_steps["sort"] = point.sort_set(self._es) self._section = "sweep-right-to-left" elif self._section == "sweep-right-to-left": - event = self._es.pop(0) + event = self._es.pop(-1) if self._sss["min"] is None or self._sss["max"] is None: self._sss["min"] = event + self._result["rb"].append(event) self._sss["max"] = event + self._result["rt"].append(event) elif event.get_y() < self._sss["min"].get_y(): - self._result["rb"].append(linesegment.LineSegment(self._sss["min"], event)) + self._result["rb"].append(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._result["rt"].append(event) self._sss["max"] = event super().step() if len(self._es) == 0: + self._es = copy.deepcopy(self._result["lt"]) self._section = "sweep-left-to-top" elif self._section == "sweep-left-to-top": event = self._es.pop(0) + self._sss["lt"].append(event) + start_idx = len(self._sss["lt"]) - 1 + for i in range(start_idx, 0, -1): + if len(self._es) > 0: + slope_a = linesegment.LineSegment( \ + self._sss["lt"][i-1], self._sss["lt"][i]).get_slope() + slope_b = linesegment.LineSegment(self._sss["lt"][i], self._es[0]).get_slope() + super().step() + if slope_a < slope_b: + del self._sss["lt"][i] + else: + break + else: + break if len(self._es) == 0: + self._result["lt"] = copy.deepcopy(self._sss["lt"]) + self._es = copy.deepcopy(self._result["lb"]) self._section = "sweep-left-to-bottom" elif self._section == "sweep-left-to-bottom": event = self._es.pop(0) + self._sss["lb"].append(event) + start_idx = len(self._sss["lb"]) - 1 + for i in range(start_idx, 0, -1): + if len(self._es) > 0: + slope_a = linesegment.LineSegment( \ + self._sss["lb"][i-1], self._sss["lb"][i]).get_slope() + slope_b = linesegment.LineSegment(self._sss["lb"][i], self._es[0]).get_slope() + super().step() + if slope_a > slope_b: + del self._sss["lb"][i] + else: + break + else: + break if len(self._es) == 0: + self._result["lb"] = copy.deepcopy(self._sss["lb"]) + self._es = copy.deepcopy(self._result["rt"]) self._section = "sweep-right-to-top" elif self._section == "sweep-right-to-top": event = self._es.pop(0) + self._sss["rt"].append(event) + start_idx = len(self._sss["rt"]) - 1 + for i in range(start_idx, 0, -1): + if len(self._es) > 0: + slope_a = linesegment.LineSegment( \ + self._sss["rt"][i-1], self._sss["rt"][i]).get_slope() + slope_b = linesegment.LineSegment(self._sss["rt"][i], self._es[0]).get_slope() + super().step() + if slope_a > slope_b: + del self._sss["rt"][i] + else: + break + else: + break if len(self._es) == 0: + self._result["rt"] = copy.deepcopy(self._sss["rt"]) + self._es = copy.deepcopy(self._result["rb"]) self._section = "sweep-right-to-bottom" elif self._section == "sweep-right-to-bottom": event = self._es.pop(0) + self._sss["rb"].append(event) + start_idx = len(self._sss["rb"]) - 1 + for i in range(start_idx, 0, -1): + if len(self._es) > 0: + slope_a = linesegment.LineSegment( \ + self._sss["rb"][i-1], self._sss["rb"][i]).get_slope() + slope_b = linesegment.LineSegment(self._sss["rb"][i], self._es[0]).get_slope() + super().step() + if slope_a < slope_b: + del self._sss["rb"][i] + else: + break + else: + break if len(self._es) == 0: + self._result["rb"] = copy.deepcopy(self._sss["rb"]) 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) + for i in range(len(self._result["lb"]) - 1): + self._result["hull"].append(self._result["lb"][i]) + for i in range(len(self._result["rb"]) - 1, 0, -1): + self._result["hull"].append(self._result["rb"][i]) + for i in range(len(self._result["rt"]) - 1): + self._result["hull"].append(self._result["rt"][i]) + for i in range(len(self._result["lt"]) - 1, 0, -1): + self._result["hull"].append(self._result["lt"][i]) self._result["success"] = True self._running = False - - + def draw(self, canvas, width, height, max_x, max_y): + if self._running: + pass + else: + for i in range(len(self._result["hull"]) - 1): + linesegment.LineSegment( \ + self._result["hull"][i], self._result["hull"][i+1]) \ + .draw(canvas, width, height, max_x, max_y, "#FF0000") + linesegment.LineSegment( \ + self._result["hull"][-1], self._result["hull"][0]) \ + .draw(canvas, width, height, max_x, max_y, "#FF0000") + for pnt in self._input: + if pnt in self._result["hull"]: + pnt.draw(canvas, width, height, max_x, max_y, "#000000") + else: + pnt.draw(canvas, width, height, max_x, max_y, "#777777")