def _remove(self, site, points, triangles): ''' Update the triangulation by removing the surrounding triangles and then filling this cavity with new Delaunay triangles. Challenge: Maintain neighborhood control. Ref: Mir Abolfazl Mostafavi, Christopher Gold, and Maciej Dakowicz. 2003. Delete and insert operations in Voronoi/Delaunay methods and applications. Comput. Geosci. 29, 4 (May 2003), 523-530. DOI=10.1016/S0098-3004(03)00017-7 http://dx.doi.org/10.1016/S0098-3004(03)00017-7 ''' # verify compatibility of surrounding points and old triangles if len(points) != len(triangles): raise Exception("Triangulation has different sizes.") # verify is the triangulation is empty (or insufficient?) if len(points) < 3: return # initialize new triangulation controls i = -1 new_triangles = {} # while there are points to form more than the last triangle while len(points) > 3: # checks the possible triangles considering # all three consecutive points (i, i1, i2 in a cycle) # of surrounding points of the site i += 1 npoints = len(points) if (i >= npoints): raise Exception("Inexists a valid ear? Is it possible?") i1 = (i + 1) % npoints i2 = (i1 + 1) % npoints # verify if points represent a valid triangle to site, # like a ear listen to the site: # 1: gets triangle orientation (CW or CCW) o_ear = Triangle.orientation(points[i], points[i1], points[i2]) # 2: gets direction of triangle to the site (CW or CCW) o_ear_site = Triangle.orientation(points[i], points[i2], site) # 3: if points are collinear, try another edge as a reference # ??why don't take this edge at first place?? if o_ear_site == 0: o_ear_site = Triangle.orientation(points[i], points[i1], site) # 4: the directions is the same? if (o_ear * o_ear_site) > 0: # if so, this a valid ear (possible triangulation) valid_ear = Triangle(points[i], points[i1], points[i2]) # verify if this ear is a Delaunay Triangulation ear_is_delaunay = True # 1. for all other surrounding points for p in points: # 1.1: is this other point (not in ear)? if not valid_ear.contains(p): # verify if ear won't circumcircle it if valid_ear.circumscribe(p): # if circumcircle, ear is not a Delaunay triangle ear_is_delaunay = False break # if it is a Delaunay triangle... if ear_is_delaunay: # include to new triangle control new_triangles[valid_ear] = None # include to neighborhood control self.neighborhood[valid_ear] = {} # link to the opposite triangles from the removed vertices self._link_ear(site, valid_ear, triangles[i], new_triangles) self._link_ear(site, valid_ear, triangles[i1], new_triangles) # change triangle related to vertex by the new one # remove old triangle by switching the diagonal triangles[i] = valid_ear # remove middle point (leave the corners) del points[i1] del triangles[i1] # restart cycle of surrounding points i = -1 # if has only three neighbours remaining in the surrounding points, # merged these three points (triangles) into last triangulation last_ear = Triangle(points[0], points[1], points[2]) self.neighborhood[last_ear] = {} new_triangles[last_ear] = None # last triangle closes the triangulation and # needs update the link with all sides (neighborhood) self._link_ear(site, last_ear, triangles[0], new_triangles) self._link_ear(site, last_ear, triangles[1], new_triangles) self._link_ear(site, last_ear, triangles[2], new_triangles) if self.main_site is not None: if self.main_site == site: self.main_site = None self._new_version() if self.check_triangulation: if not self.valid(): print "### Removing failure"