File: _triangulation_debugger.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 (171 lines) | stat: -rw-r--r-- 5,231 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
171
# -*- coding: utf-8 -*-
"""
Debugging system for Triangulation class. Displays stepwise visual 
representation of the algorithm. 

This system currently requires pyqtgraph for its visual output.
"""
from __future__ import division

import numpy as np
import time

from ..util.geometry.triangulation import Triangulation


class DebugTriangulation(Triangulation):
    """ 
    Visualize triangulation process stepwise to aid in debugging.
    
    *interval* specifies the diration to wait before drawing each update in
    the triangulation procedure. Negative values cause the display to wait
    until the user clicks on the window for each update.
    
    *skip* causes the display to immediately process the first N events
    before pausing.
    """
    def __init__(self, pts, edges, interval=0.01, skip=0):
        self.interval = interval
        self.iteration = 0
        self.skip = skip 
        
        Triangulation.__init__(self, pts, edges)
        
        # visual #debugging: draw edges, front, triangles
        self.win = pg.plot()
        self.graph = pg.GraphItem(pos=pts.copy(), adj=edges.copy(), 
                                  pen={'width': 3, 'color': (0, 100, 0)})
        self.win.addItem(self.graph)
        self.front_line = pg.PlotCurveItem(pen={'width': 2, 
                                                'dash': [5, 5], 
                                                'color': 'y'})
        self.win.addItem(self.front_line)
        self.tri_shapes = {}
        
        self.nextStep = False
        self.win.scene().sigMouseClicked.connect(self.mouseClicked)

    def mouseClicked(self):
        self.nextStep = True
        
    def draw_state(self):
        global app
        print("State %s" % self.iteration)
        self.iteration += 1
        if self.iteration <= self.skip:
            return
        
        front_pts = self.pts[np.array(self.front)]
        self.front_line.setData(front_pts[:, 0], front_pts[:, 1])
        self.graph.setData(pos=self.pts, adj=self.edges) 
        
        # Auto-advance on timer
        if self.interval < 0:
            #Advance once per click
            while True:
                app.processEvents()
                time.sleep(0.01)
                if self.nextStep:
                    self.nextStep = False
                    break
        else:
            # sleep, but keep ui responsive
            for i in range(int(self.interval / 0.01)):
                app.processEvents()
                time.sleep(0.01)
            
    def draw_tri(self, tri, source=None):
        # assign triangle color based on the source that generated it
        color = {
            None: (0, 255, 255, 50),
            'smooth1': (0, 255, 0, 50),
            'fill_hull': (255, 255, 0, 50),
            'edge_event': (100, 100, 255, 100),
        }[source]
        
        tpts = self.pts[np.array(tri)]
        path = pg.arrayToQPath(tpts[:, 0], tpts[:, 1])
        shape = pg.QtGui.QGraphicsPathItem(path)
        shape.setPen(pg.mkPen(255, 255, 255, 100))
        brush = pg.mkBrush(color)
        shape.setBrush(brush)
        self.win.addItem(shape)
        self.tri_shapes[tri] = shape
        self.draw_state()

    def undraw_tri(self, tri):
        shape = self.tri_shapes.pop(tri)
        self.win.removeItem(shape)
        self.draw_state()
        
    def add_tri(self, *args, **kwargs):
        Triangulation._add_tri(self, *args, **kwargs)
        self.draw_tri(list(self.tris.keys())[-1], 
                      source=kwargs.get('source', None))
    
    def remove_tri(self, *args, **kwargs):
        k = Triangulation._remove_tri(self, *args, **kwargs)
        self.undraw_tri(k)

    def edge_event(self, *args, **kwargs):
        self.draw_state()
        Triangulation._edge_event(self, *args, **kwargs)
        self.draw_state()


if __name__ == '__main__':
    import pyqtgraph as pg
    
    app = pg.mkQApp()
    
    #user input data - points and constraining edges
    
    #
    #  Test 1
    #
    pts = [(0, 0),
           (10, 0),
           (10, 10),
           (20, 10),
           (20, 20),
           (25, 20),
           (25, 25),
           (20, 25),
           (20, 20),
           (10, 17),
           (5, 25),
           (9, 30),
           (6, 15),
           (15, 12.5),
           (0, 5)]
    num_pts = len(pts)
    edges = [(i, (i+1) % num_pts) for i in range(num_pts)]
    pts += [(21, 21),
            (24, 21),
            (24, 24),
            (21, 24)]
    edges += [(num_pts, num_pts + 1),
              (num_pts + 1, num_pts + 2),
              (num_pts + 2, num_pts + 3),
              (num_pts + 3, num_pts)]

    pts = np.array(pts, dtype=float)
    edges = np.array(edges, dtype=int)

    #t = DebugTriangulation(pts, edges, interval=-1, skip=19570)
    #t.triangulate()

    # make lines that are entirely vertical / horizontal
    np.random.seed(1)
    N = 100
    pts = [[0, 0]]
    for i in range(N - 1):
        p = pts[-1][:]
        p[i % 2] += np.random.normal()
        pts.append(p)
    pts = np.array(pts)
    edges = np.zeros((N, 2), dtype=int)
    edges[:, 0] = np.arange(N)
    edges[:, 1] = np.arange(1, N + 1) % N
    t = DebugTriangulation(pts, edges)
    t.triangulate()