def __cleanup_mask(self): mask = self.get_mask() # Drop points from all shapes which are not part of the convex hulls. for shape in mask: if len(shape) <= 3: continue points = [self.get_pos_for_color(c) for c in shape] edge_points = geom.convex_hull(points) for col, point in zip(shape, points): if point in edge_points: continue shape.remove(col) # Drop shapes smaller than the minimum size. newmask = [] min_size = self.get_radius() * self.min_shape_size for shape in mask: points = [self.get_pos_for_color(c) for c in shape] void = geom.convex_hull(points) size = self._get_void_size(void) if size >= min_size: newmask.append(shape) mask = newmask # Drop shapes whose points entirely lie within other shapes newmask = [] maskvoids = [ (shape, geom.convex_hull([self.get_pos_for_color(c) for c in shape])) for shape in mask ] for shape1, void1 in maskvoids: shape1_subsumed = True for p1 in void1: p1_subsumed = False for shape2, void2 in maskvoids: if shape1 is shape2: continue if geom.point_in_convex_poly(p1, void2): p1_subsumed = True break if not p1_subsumed: shape1_subsumed = False break if not shape1_subsumed: newmask.append(shape1) mask = newmask self.set_mask(mask) self.queue_draw()
def __cleanup_mask(self): mask = self.get_mask() # Drop points from all shapes which are not part of the convex hulls. for shape in mask: if len(shape) <= 3: continue points = [self.get_pos_for_color(c) for c in shape] edge_points = geom.convex_hull(points) for col, point in zip(shape, points): if point in edge_points: continue shape.remove(col) # Drop shapes smaller than the minimum size. newmask = [] min_size = self.get_radius() * self.min_shape_size for shape in mask: points = [self.get_pos_for_color(c) for c in shape] void = geom.convex_hull(points) size = self._get_void_size(void) if size >= min_size: newmask.append(shape) mask = newmask # Drop shapes whose points entirely lie within other shapes newmask = [] maskvoids = [(shape, geom.convex_hull([self.get_pos_for_color(c) for c in shape])) for shape in mask] for shape1, void1 in maskvoids: shape1_subsumed = True for p1 in void1: p1_subsumed = False for shape2, void2 in maskvoids: if shape1 is shape2: continue if geom.point_in_convex_poly(p1, void2): p1_subsumed = True break if not p1_subsumed: shape1_subsumed = False break if not shape1_subsumed: newmask.append(shape1) mask = newmask self.set_mask(mask) self.queue_draw()
def geometry(self): hull = geom.convex_hull(self.stops()) return { 'type': 'Polygon', 'coordinates': [ hull + [hull[0]] ] }
def colors_to_mask_void(self, colors): """Converts a set of colours to a mask void (convex hull). Mask voids are the convex hulls of the (x, y) positions for the colours making up the mask, so mask shapes with fewer than 3 colours are returned as the empty list. """ points = [] if len(colors) < 3: return points for col in colors: points.append(self.get_pos_for_color(col)) return geom.convex_hull(points)
def __update_active_objects(self, x, y): # Decides what a click or a drag at (x, y) would do, and updates the # mouse cursor and draw state to match. assert self.__drag_func is None self.__active_shape = None self.__active_ctrlpoint = None self.__tmp_new_ctrlpoint = None self.queue_draw() # yes, always # Possible mask void manipulations mask = self.get_mask() for mask_idx in xrange(len(mask)): colors = mask[mask_idx] if len(colors) < 3: continue # If the pointer is near an existing control point, clicking and # dragging will move it. void = [] for col_idx in xrange(len(colors)): col = colors[col_idx] px, py = self.get_pos_for_color(col) dp = math.sqrt((x-px)**2 + (y-py)**2) if dp <= self.__ctrlpoint_grab_radius: mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__active_ctrlpoint = col_idx self.__set_cursor(None) return void.append((px, py)) # If within a certain distance of an edge, dragging will create and # then move a new control point. void = geom.convex_hull(void) for p1, p2 in geom.pairwise(void): isect = geom.nearest_point_in_segment(p1, p2, (x, y)) if isect is not None: ix, iy = isect di = math.sqrt((ix-x)**2 + (iy-y)**2) if di <= self.__ctrlpoint_grab_radius: newcol = self.get_color_at_position(ix, iy) self.__tmp_new_ctrlpoint = newcol mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__set_cursor(None) return # If the mouse is within a mask void, then dragging would move that # shape around within the mask. if geom.point_in_convex_poly((x, y), void): mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__set_cursor(None) return # Away from shapes, clicks and drags manipulate the entire mask: adding # cutout voids to it, or rotating the whole mask around its central # axis. alloc = self.get_allocation() cx, cy = self.get_center(alloc=alloc) radius = self.get_radius(alloc=alloc) dx, dy = x-cx, y-cy r = math.sqrt(dx**2 + dy**2) if r < radius*(1.0-self.min_shape_size): if len(mask) < self.__max_num_shapes: d = self.__dist_to_nearest_shape(x, y) minsize = radius * self.min_shape_size if d is None or d > minsize: # Clicking will result in a new void self.__set_cursor(self.__add_cursor) else: # Click-drag to rotate the entire mask self.__set_cursor(self.__rotate_cursor)
def geometry(self): hull = geom.convex_hull(self.stops()) return {'type': 'Polygon', 'coordinates': [hull + [hull[0]]]}
def test_convex_hull(self): expect = [[0, 1], [1, 0], [1, 1]] data = geom.convex_hull(mockpoints()) for i,j in zip(data, expect): self.assertAlmostEqual(i[0], j[0]) self.assertAlmostEqual(i[1], j[1])
if not arcpy.Exists(new_fc): tweet.info("Creating feature class {}".format(new_fc)) result = arcpy.management.CreateFeatureclass(output_geodatabase, output_class, "POLYGON", spatial_reference=spatialRef) if not group_field is None: arcpy.AddField_management(new_fc, group_field, "TEXT") else: tweet.info("Emptying feature class {}".format(new_fc)) arcpy.DeleteFeatures_management(new_fc) insert = ['SHAPE@'] if not group_field is None: insert.append(group_field) with arcpy.da.InsertCursor(new_fc, insert) as icursor: for group in point_lists: points = point_lists[group] convex_hull = geom.convex_hull(points) concave_hull = geom.concave_hull(convex_hull, points, min_length_fraction=minimum_length, min_angle=minimum_angle, max_iterations=iteration_cap) if not group_field is None: icursor.insertRow([concave_hull, group]) else: icursor.insertRow([concave_hull])
def __update_active_objects(self, x, y): # Decides what a click or a drag at (x, y) would do, and updates the # mouse cursor and draw state to match. assert self.__drag_func is None self.__active_shape = None self.__active_ctrlpoint = None self.__tmp_new_ctrlpoint = None self.queue_draw() # yes, always # Possible mask void manipulations mask = self.get_mask() for mask_idx in xrange(len(mask)): colors = mask[mask_idx] if len(colors) < 3: continue # If the pointer is near an existing control point, clicking and # dragging will move it. void = [] for col_idx in xrange(len(colors)): col = colors[col_idx] px, py = self.get_pos_for_color(col) dp = math.sqrt((x - px)**2 + (y - py)**2) if dp <= self.__ctrlpoint_grab_radius: mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__active_ctrlpoint = col_idx self.__set_cursor(None) return void.append((px, py)) # If within a certain distance of an edge, dragging will create and # then move a new control point. void = geom.convex_hull(void) for p1, p2 in geom.pairwise(void): isect = geom.nearest_point_in_segment(p1, p2, (x, y)) if isect is not None: ix, iy = isect di = math.sqrt((ix - x)**2 + (iy - y)**2) if di <= self.__ctrlpoint_grab_radius: newcol = self.get_color_at_position(ix, iy) self.__tmp_new_ctrlpoint = newcol mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__set_cursor(None) return # If the mouse is within a mask void, then dragging would move that # shape around within the mask. if geom.point_in_convex_poly((x, y), void): mask.remove(colors) mask.insert(0, colors) self.__active_shape = colors self.__set_cursor(None) return # Away from shapes, clicks and drags manipulate the entire mask: adding # cutout voids to it, or rotating the whole mask around its central # axis. alloc = self.get_allocation() cx, cy = self.get_center(alloc=alloc) radius = self.get_radius(alloc=alloc) dx, dy = x - cx, y - cy r = math.sqrt(dx**2 + dy**2) if r < radius * (1.0 - self.min_shape_size): if len(mask) < self.__max_num_shapes: d = self.__dist_to_nearest_shape(x, y) minsize = radius * self.min_shape_size if d is None or d > minsize: # Clicking will result in a new void self.__set_cursor(self.__add_cursor) else: # Click-drag to rotate the entire mask self.__set_cursor(self.__rotate_cursor)