Source code for enable.primitives.polygon

"""A filled polygon component"""

# Major package imports.
from numpy import array

# Enthought library imports.
from kiva.api import EOF_FILL_STROKE, FILL, FILL_STROKE, points_in_polygon
from traits.api import (
    Any, Event, Float, HasTraits, Instance, List, Map, Property, Tuple
)
from traitsui.api import Group, View

# Local imports.
from enable.api import border_size_trait, Component
from enable.colors import ColorTrait


[docs]class PolygonModel(HasTraits): """ The data model for a Polygon. """ # The points that make up the vertices of this polygon. points = List(Tuple)
[docs] def reset(self): self.points = []
[docs]class Polygon(Component): """ A filled polygon component. """ # ------------------------------------------------------------------------- # Trait definitions. # ------------------------------------------------------------------------- # The background color of this polygon. background_color = ColorTrait("white") # The color of the border of this polygon. border_color = ColorTrait("black") # The dash pattern to use for this polygon. border_dash = Any # The thickness of the border of this polygon. border_size = border_size_trait(1) # Event fired when the polygon is "complete". complete = Event # The rule to use to determine the inside of the polygon. inside_rule = Map( {"winding": FILL_STROKE, "oddeven": EOF_FILL_STROKE}, default_value="winding", ) # The points that make up this polygon. model = Instance(PolygonModel, ()) # Convenience property to access the model's points. points = Property # The color of each vertex. vertex_color = ColorTrait("black") # The size of each vertex. vertex_size = Float(3.0) traits_view = View( Group("<component>", id="component"), Group("<links>", id="links"), Group( "background_color", "_", "border_color", "_", "border_size", id="Box", style="custom", ), ) colorchip_map = {"color": "color", "alt_color": "border_color"} # ------------------------------------------------------------------------- # Traits property accessors # ------------------------------------------------------------------------- def _get_points(self): return self.model.points # ------------------------------------------------------------------------- # 'Polygon' interface # -------------------------------------------------------------------------
[docs] def reset(self): "Reset the polygon to the initial state" self.model.reset() self.event_state = "normal"
# ------------------------------------------------------------------------- # 'Component' interface # ------------------------------------------------------------------------- def _draw_mainlayer(self, gc, view_bounds=None, mode="normal"): "Draw the component in the specified graphics context" self._draw_closed(gc) # ------------------------------------------------------------------------- # Protected interface # ------------------------------------------------------------------------- def _is_in(self, point): """ Test if the point (an x, y tuple) is within this polygonal region. To perform the test, we use the winding number inclusion algorithm, referenced in the comp.graphics.algorithms FAQ (http://www.faqs.org/faqs/graphics/algorithms-faq/) and described in detail here: http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm """ point_array = array((point,)) vertices = array(self.model.points) winding = self.inside_rule == "winding" result = points_in_polygon(point_array, vertices, winding) return result[0] # ------------------------------------------------------------------------- # Private interface # ------------------------------------------------------------------------- def _draw_closed(self, gc): "Draw this polygon as a closed polygon" if len(self.model.points) > 2: # Set the drawing parameters. gc.set_fill_color(self.background_color_) gc.set_stroke_color(self.border_color_) gc.set_line_width(self.border_size) gc.set_line_dash(self.border_dash) # Draw the path. gc.begin_path() gc.move_to( self.model.points[0][0] - self.x, self.model.points[0][1] + self.y, ) offset_points = [ (x - self.x, y + self.y) for x, y in self.model.points ] gc.lines(offset_points) gc.close_path() gc.draw_path(self.inside_rule_) # Draw the vertices. self._draw_vertices(gc) def _draw_open(self, gc): "Draw this polygon as an open polygon" if len(self.model.points) > 2: # Set the drawing parameters. gc.set_fill_color(self.background_color_) gc.set_stroke_color(self.border_color_) gc.set_line_width(self.border_size) gc.set_line_dash(self.border_dash) # Draw the path. gc.begin_path() gc.move_to( self.model.points[0][0] - self.x, self.model.points[0][1] + self.y, ) offset_points = [ (x - self.x, y + self.y) for x, y in self.model.points ] gc.lines(offset_points) gc.draw_path(self.inside_rule_) # Draw the vertices. self._draw_vertices(gc) def _draw_vertices(self, gc): "Draw the vertices of the polygon." gc.set_fill_color(self.vertex_color_) gc.set_line_dash(None) offset = self.vertex_size / 2.0 offset_points = [ (x + self.x, y + self.y) for x, y in self.model.points ] if hasattr(gc, "draw_path_at_points"): path = gc.get_empty_path() path.rect(-offset, -offset, self.vertex_size, self.vertex_size) gc.draw_path_at_points(offset_points, path, FILL_STROKE) else: for x, y in offset_points: gc.draw_rect( ( x - offset, y - offset, self.vertex_size, self.vertex_size, ), FILL, )