Example #1
0
    def get_color_at_position(self, x, y, ignore_mask=False):
        """Converts an `x`, `y` position to a color.

        Ordinarily, this implmentation uses any active mask to limit the
        colors which can be clicked on. Set `ignore_mask` to disable this
        added behaviour.

        """
        sup = HueSaturationWheelMixin
        if ignore_mask or not self.mask_toggle.get_active():
            return sup.get_color_at_position(self, x, y)
        voids = self.get_mask_voids()
        if not voids:
            return sup.get_color_at_position(self, x, y)
        isects = []
        for vi, void in enumerate(voids):
            # If we're inside a void, use the unchanged value
            if geom.point_in_convex_poly((x, y), void):
                return sup.get_color_at_position(self, x, y)
            # If outside, find the nearest point on the nearest void's edge
            for p1, p2 in geom.pairwise(void):
                isect = geom.nearest_point_in_segment(p1, p2, (x, y))
                if isect is not None:
                    d = math.sqrt((isect[0] - x)**2 + (isect[1] - y)**2)
                    isects.append((d, isect))
                # Above doesn't include segment ends, so add those
                d = math.sqrt((p1[0] - x)**2 + (p1[1] - y)**2)
                isects.append((d, p1))
        # Determine the closest point.
        if isects:
            isects.sort()
            x, y = isects[0][1]
        return sup.get_color_at_position(self, x, y)
Example #2
0
    def get_color_at_position(self, x, y, ignore_mask=False):
        """Converts an `x`, `y` position to a color.

        Ordinarily, this implmentation uses any active mask to limit the
        colors which can be clicked on. Set `ignore_mask` to disable this
        added behaviour.

        """
        sup = HueSaturationWheelMixin
        if ignore_mask or not self.mask_toggle.get_active():
            return sup.get_color_at_position(self, x, y)
        voids = self.get_mask_voids()
        if not voids:
            return sup.get_color_at_position(self, x, y)
        isects = []
        for vi, void in enumerate(voids):
            # If we're inside a void, use the unchanged value
            if geom.point_in_convex_poly((x, y), void):
                return sup.get_color_at_position(self, x, y)
            # If outside, find the nearest point on the nearest void's edge
            for p1, p2 in geom.pairwise(void):
                isect = geom.nearest_point_in_segment(p1, p2, (x, y))
                if isect is not None:
                    d = math.sqrt((isect[0]-x)**2 + (isect[1]-y)**2)
                    isects.append((d, isect))
                # Above doesn't include segment ends, so add those
                d = math.sqrt((p1[0]-x)**2 + (p1[1]-y)**2)
                isects.append((d, p1))
        # Determine the closest point.
        if isects:
            isects.sort()
            x, y = isects[0][1]
        return sup.get_color_at_position(self, x, y)
Example #3
0
 def __dist_to_nearest_shape(self, x, y):
     # Distance from `x`, `y` to the nearest edge or vertex of any shape.
     dists = []
     for hull in self.get_mask_voids():
         # cx, cy = geom.poly_centroid(hull)
         for p1, p2 in geom.pairwise(hull):
             np = geom.nearest_point_in_segment(p1, p2, (x, y))
             if np is not None:
                 nx, ny = np
                 d = math.sqrt((x - nx)**2 + (y - ny)**2)
                 dists.append(d)
         # Segment end too
         d = math.sqrt((p1[0] - x)**2 + (p1[1] - y)**2)
         dists.append(d)
     if not dists:
         return None
     dists.sort()
     return dists[0]
Example #4
0
 def __dist_to_nearest_shape(self, x, y):
     # Distance from `x`, `y` to the nearest edge or vertex of any shape.
     dists = []
     for hull in self.get_mask_voids():
         # cx, cy = geom.poly_centroid(hull)
         for p1, p2 in geom.pairwise(hull):
             nearest_point = geom.nearest_point_in_segment(p1, p2, (x, y))
             if nearest_point is not None:
                 nx, ny = nearest_point
                 d = math.sqrt((x-nx)**2 + (y-ny)**2)
                 dists.append(d)
         # Segment end too
         d = math.sqrt((p1[0]-x)**2 + (p1[1]-y)**2)
         dists.append(d)
     if not dists:
         return None
     dists.sort()
     return dists[0]
Example #5
0
    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)
Example #6
0
    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)