File: ellipse.py

package info (click to toggle)
python-vispy 0.6.6-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 21,240 kB
  • sloc: python: 57,407; javascript: 6,810; makefile: 63; sh: 5
file content (170 lines) | stat: -rw-r--r-- 5,152 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.


"""
Simple ellipse visual based on PolygonVisual
"""

from __future__ import division

import numpy as np
from .polygon import PolygonVisual


class EllipseVisual(PolygonVisual):
    """
    Displays a 2D ellipse

    Parameters
    ----------
    center : array
        Center of the ellipse
    color : instance of Color
        The face color to use.
    border_color : instance of Color
        The border color to use.
    border_width: float
        The width of the border in pixels
        Line widths > 1px are only
        guaranteed to work when using `border_method='agg'` method.
    radius : float | tuple
        Radius or radii of the ellipse
        Defaults to  (0.1, 0.1)
    start_angle : float
        Start angle of the ellipse in degrees
        Defaults to 0.
    span_angle : float
        Span angle of the ellipse in degrees
        Defaults to 360.
    num_segments : int
        Number of segments to be used to draw the ellipse
        Defaults to 100
    **kwargs : dict
        Keyword arguments to pass to `PolygonVisual`.
    """
    def __init__(self, center=None, color='black', border_color=None,
                 border_width=1, radius=(0.1, 0.1), start_angle=0.,
                 span_angle=360., num_segments=100, **kwargs):
        self._center = center
        self._radius = radius
        self._start_angle = start_angle
        self._span_angle = span_angle
        self._num_segments = num_segments

        # triangulation can be very slow
        kwargs.setdefault('triangulate', False)
        PolygonVisual.__init__(self, pos=None, color=color,
                               border_color=border_color,
                               border_width=border_width, **kwargs)

        self._mesh.mode = "triangle_fan"
        self._regen_pos()
        self._update()

    @staticmethod
    def _generate_vertices(center, radius, start_angle, span_angle,
                           num_segments):
        if isinstance(radius, (list, tuple)):
            if len(radius) == 2:
                xr, yr = radius
            else:
                raise ValueError("radius must be float or 2 value tuple/list"
                                 " (got %s of length %d)" % (type(radius),
                                                             len(radius)))
        else:
            xr = yr = radius

        start_angle = np.deg2rad(start_angle)

        vertices = np.empty([num_segments + 2, 2], dtype=np.float32)

        # split the total angle into num_segments intances
        theta = np.linspace(start_angle,
                            start_angle + np.deg2rad(span_angle),
                            num_segments + 1)

        # PolarProjection
        vertices[1:, 0] = center[0] + xr * np.cos(theta)
        vertices[1:, 1] = center[1] + yr * np.sin(theta)

        # specify center point (not used in border)
        vertices[0] = np.float32([center[0], center[1]])

        return vertices

    @property
    def center(self):
        """ The center of the ellipse
        """
        return self._center

    @center.setter
    def center(self, center):
        """ The center of the ellipse
        """
        self._center = center
        self._regen_pos()
        self._update()

    @property
    def radius(self):
        """ The start radii of the ellipse.
        """
        return self._radius

    @radius.setter
    def radius(self, radius):
        self._radius = radius
        self._regen_pos()
        self._update()

    @property
    def start_angle(self):
        """ The start start_angle of the ellipse.
        """
        return self._start_angle

    @start_angle.setter
    def start_angle(self, start_angle):
        self._start_angle = start_angle
        self._regen_pos()
        self._update()

    @property
    def span_angle(self):
        """ The angular span of the ellipse.
        """
        return self._span_angle

    @span_angle.setter
    def span_angle(self, span_angle):
        self._span_angle = span_angle
        self._regen_pos()
        self._update()

    @property
    def num_segments(self):
        """ The number of segments in the ellipse.
        """
        return self._num_segments

    @num_segments.setter
    def num_segments(self, num_segments):
        num_segments = int(num_segments)
        if num_segments < 1:
            raise ValueError('EllipseVisual must consist of more than 1 '
                             'segment')
        self._num_segments = num_segments
        self._regen_pos()
        self._update()

    def _regen_pos(self):
        vertices = self._generate_vertices(center=self._center,
                                           radius=self._radius,
                                           start_angle=self._start_angle,
                                           span_angle=self._span_angle,
                                           num_segments=self._num_segments)
        # don't use the center point
        self._pos = vertices[1:]