Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_wx/ogleditor.py
169689 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
4
# SUMOPy module
5
# Copyright (C) 2012-2021 University of Bologna - DICAM
6
# This program and the accompanying materials are made available under the
7
# terms of the Eclipse Public License 2.0 which is available at
8
# https://www.eclipse.org/legal/epl-2.0/
9
# This Source Code may also be made available under the following Secondary
10
# Licenses when the conditions for such availability set forth in the Eclipse
11
# Public License 2.0 are satisfied: GNU General Public License, version 2
12
# or later which is available at
13
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
14
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
15
16
# @file ogleditor.py
17
# @author Joerg Schweizer
18
# @date 2012
19
20
"""OpenGL editor"""
21
import types
22
import os
23
import sys
24
from toolbox import *
25
from wxmisc import *
26
from agilepy.lib_base.geometry import *
27
import agilepy.lib_base.arrayman as am
28
import agilepy.lib_base.classman as cm
29
from wx.lib.buttons import GenBitmapTextButton, GenBitmapButton
30
from wx import glcanvas
31
from collections import OrderedDict
32
import wx
33
if __name__ == '__main__':
34
__version__ = "0.3"
35
__licence__ = """licensed under the GPL."""
36
__copyright__ = "(c) 2012-2018 University of Bologna - DICAM"
37
__author__ = "Joerg Schweizer"
38
39
__usage__ = """USAGE:
40
from command line:
41
python ogleditor.py
42
python ogleditor.py <scenariobasename> <scenariodir>
43
44
use for debugging
45
python ogleditor.py --debug > debug.txt 2>&1
46
"""
47
print __copyright__
48
49
###############################################################################
50
# IMPORTS
51
52
#import wxversion
53
# wxversion.select("2.8")
54
55
try:
56
from OpenGL.GL import *
57
from OpenGL.GLU import * # project , unproject , tess
58
from OpenGL.GLUT import *
59
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, \
60
glBindVertexArray
61
62
from OpenGL.arrays import vbo
63
import numpy as np
64
65
except ImportError:
66
raise ImportError, "Required dependencies numpy or OpenGL not present"
67
68
if __name__ == '__main__':
69
try:
70
FILEDIR = os.path.dirname(os.path.abspath(__file__))
71
except:
72
FILEDIR = os.path.dirname(os.path.abspath(sys.argv[0]))
73
sys.path.append(os.path.join(FILEDIR, "..", ".."))
74
#IMAGEDIR = os.path.join(APPDIR,"lib_base","images")
75
76
IMAGEDIR = os.path.join(os.path.dirname(__file__), "images")
77
78
79
# wx gui stuff
80
81
82
FLATHEAD = 0
83
BEVELHEAD = 1
84
TRIANGLEHEAD = 2
85
ARROWHEAD = 3
86
LEFTTRIANGLEHEAD = 4
87
RIGHTTRIANGLEHEAD = 5
88
89
LINEHEADS = { # 'flat':0,# not a style
90
'bevel': BEVELHEAD,
91
'triangle': TRIANGLEHEAD,
92
'arrow': ARROWHEAD,
93
'lefttriangle': LEFTTRIANGLEHEAD,
94
'righttriangle': RIGHTTRIANGLEHEAD,
95
}
96
97
# to be deleted
98
99
###############################################################################
100
# vbo test
101
vertices = [
102
[0.1, 0.1, 0], # 0
103
[0.1, 0.5, 0.5], # 1
104
[0, 0.9, 0], # 2
105
[0.2, 0.0, 0], # 3
106
[0.5, 0.0, 0], # 4
107
[0.9, 0, 0], # 5
108
[0.2, 0.2, 0.5], # 6
109
[0.5, 0.5, 0.5], # 7
110
[0.9, 0.9, 0], # 8
111
]
112
113
indexes = [
114
0, 1,
115
2, 7,
116
5, 6,
117
]
118
119
colors = [
120
[0.9, 0.9, 0.0, 0.9], # 0
121
[0.9, 0.9, 0.0, 0.9], # 1
122
[0.9, 0.0, 0.9, 0.9], # 2
123
[0.9, 0.0, 0.9, 0.9], # 3
124
[0.0, 0.9, 0.9, 0.9], # 4
125
[0.0, 0.9, 0.9, 0.9], # 5
126
[0.0, 0.9, 0.9, 0.9], # 6
127
[0.9, 0.0, 0.9, 0.9], # 7
128
[0.9, 0.0, 0.9, 0.9], # 8
129
]
130
131
# Create the VBO
132
vertexarray = np.array(vertices, dtype=np.float32)
133
indexarray = np.array(indexes, dtype=np.int32)
134
135
vertexvbo = vbo.VBO(vertexarray)
136
indexvbo = vbo.VBO(indexarray, target=GL_ELEMENT_ARRAY_BUFFER)
137
138
colorarray = np.array(colors, dtype=np.float32)
139
colorvbo = vbo.VBO(colorarray)
140
141
###############################################################################
142
143
144
#import test_glcanvas as testogl
145
# class TestVbo(Vbo):
146
# def draw(self, resolution):
147
##
148
##
149
##
150
# print 'draw',self.get_ident(),self
151
# glEnableClientState(GL_VERTEX_ARRAY)
152
# glEnableClientState(GL_COLOR_ARRAY)
153
##
154
# self._colorvbo.bind()
155
## glColorPointer(4, GL_FLOAT, 0, None)
156
##
157
# self._vertexvbo.bind()
158
# self._indexvbo.bind()
159
## glVertexPointer(3, GL_FLOAT, 0, None)
160
##
161
# print ' self._n_vpo *(self._n_vpo-1)*self._n_drawobjs',self._n_vpo *(self._n_vpo-1)*self._n_drawobjs
162
# print ' len(self._vertexvbo)',len(self._vertexvbo)
163
# print ' len(self._colorvbo)',len(self._colorvbo)
164
# n_vpo = len(self._vertexvbo)/self._n_vpe/self._n_drawobjs+1
165
# glDrawElements(self._glelement, self._n_vpo *(self._n_vpo-1)*self._n_drawobjs, GL_UNSIGNED_INT, None)
166
## glDrawElements(self._glelement, len(self._vertexvbo), GL_UNSIGNED_INT, None)
167
##
168
# glDisableClientState(GL_VERTEX_ARRAY)
169
# glDisableClientState(GL_COLOR_ARRAY)
170
##
171
# self._vertexvbo.unbind()
172
# self._indexvbo.unbind()
173
# self._colorvbo.unbind()
174
175
def normalize(v):
176
norm = np.linalg.norm(v)
177
if norm == 0:
178
return v
179
return v/norm
180
181
182
class Vbo:
183
def __init__(self, ident, glelement, n_vpe, objtype=''):
184
self._ident = ident
185
self._glelement = glelement
186
self._n_vpe = n_vpe
187
self._objtype = objtype
188
self.reset()
189
190
def reset(self):
191
self._vertexvbo = None
192
self._indexvbo = None
193
self._colorvbo = None
194
self._inds = None
195
196
def get_objtype(self):
197
return self._objtype
198
199
def is_fill(self):
200
return self._objtype == 'fill'
201
202
def get_ident(self):
203
return self._ident
204
205
def get_vpe(self):
206
return self._n_vpe
207
208
def update_vertices(self, vertices, n=None, inds=None):
209
"""
210
211
n = number of draw objects
212
"""
213
self._inds = inds
214
# print 'update_vertices',self.get_ident(),n
215
self._n_drawobjs = n
216
#
217
#vertices = np.zeros((self._n_elem_fill, self._n_vpe_fill * 3),dtype=np.float32)
218
# len(vertices) = n_elem = (n_vpo-1)*n
219
#n_elem = len(vertices)/n_drawobjs+self._noncyclic
220
221
# n_vpo = vertex per draw object
222
# n_elem = (n_vpo-1)*n_drawobjs
223
# n_vpo = vertex per draw object
224
#self._n_vpo = n_elem/n_drawobjs+1
225
#n_vert = len(self._vertexvbo_fill)/self._n_vpe_fill/len(self)+1
226
#n_elem_fill = (n_vert-1)*n
227
# len(_vertexvbo_fill) = self._n_vpe * self._n_elem_fill = self._n_vpe * (n_vert-1)*n
228
# print ' len(vertices),n_vpo,n_elem',len(vertices),self._n_vpo,n_elem
229
230
#glDrawElements(GL_TRIANGLES, self._n_vert*self._n_elem_fill, GL_UNSIGNED_INT, None)
231
# self._n_vert*self._n_elem_fill = n_vert * (n_vert-1)*n
232
# repeat for each of the n objects: self._n_vpe_fill*(n_vert-1)
233
# print ' vertices=\n',vertices
234
# print ' vertices.reshape((-1,3))=\n',vertices.reshape((-1,3))
235
self._vertexvbo = vbo.VBO(vertices.reshape((-1, 3)))
236
self._indexvbo = vbo.VBO(np.arange(len(self._vertexvbo), dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
237
#self._indexvbo = vbo.VBO(np.arange(len(vertices.reshape((-1,3)) ), dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
238
239
def destroy(self):
240
del self._vertexvbo
241
del self._indexvbo
242
del self._colorvbo
243
self.reset()
244
245
def update_colors(self, colors):
246
247
if self._vertexvbo is None:
248
return
249
# print 'update_colors',self._n_drawobjs,len(colors)
250
if len(colors) == 0:
251
return
252
if self._n_drawobjs is None:
253
n_repreat = len(self._vertexvbo)/len(self._inds) # self._n_drawobjs
254
self._colorvbo = vbo.VBO(np.repeat(colors[self._inds], n_repreat, 0))
255
else:
256
n_repreat = len(self._vertexvbo)/self._n_drawobjs
257
self._colorvbo = vbo.VBO(np.repeat(colors, n_repreat, 0))
258
259
def draw(self, resolution):
260
261
# glEnableClientState(GL_VERTEX_ARRAY)
262
# glEnableClientState(GL_COLOR_ARRAY)
263
if self._vertexvbo is None:
264
return
265
# print 'Vbo.draw',self.get_ident(),self._n_drawobjs,len(self._vertexvbo)
266
# if self._n_drawobjs in (0,None): return
267
if self._n_drawobjs == 0:
268
return
269
self._colorvbo.bind()
270
glColorPointer(4, GL_FLOAT, 0, None)
271
272
self._vertexvbo.bind()
273
self._indexvbo.bind()
274
glVertexPointer(3, GL_FLOAT, 0, None)
275
276
# print ' self._n_vpo *(self._n_vpo-1)*self._n_drawobjs',self._n_vpo *(self._n_vpo-1)*self._n_drawobjs
277
# print ' len(self._vertexvbo)',len(self._vertexvbo)
278
# print ' len(self._indexvbo)',len(self._indexvbo)
279
# print ' len(self._colorvbo)',len(self._colorvbo)
280
#n_vpo = len(self._vertexvbo)/self._n_vpe/self._n_drawobjs+1
281
#glDrawElements(self._glelement, self._n_vpo *(self._n_vpo-1)*self._n_drawobjs, GL_UNSIGNED_INT, None)
282
glDrawElements(self._glelement, len(self._vertexvbo), GL_UNSIGNED_INT, None)
283
284
# glDisableClientState(GL_VERTEX_ARRAY)
285
# glDisableClientState(GL_COLOR_ARRAY)
286
287
self._vertexvbo.unbind()
288
self._indexvbo.unbind()
289
self._colorvbo.unbind()
290
291
292
class SelectToolMixin(BaseTool):
293
"""
294
Mixin for Selection tools for OGL canvas.
295
"""
296
297
def _init_select(self, is_show_selected=False, detectwidth=0.1, detectpix=5):
298
"""
299
Define selection specific attributes.
300
"""
301
self.detectpix = detectpix
302
self.detectwidth = detectwidth # in meter
303
self.is_show_selected = is_show_selected
304
305
if is_show_selected:
306
groupnames = ['options']
307
else:
308
groupnames = ['_private_']
309
self.add_col(am.TabIdsArrayConf('drawobjects',
310
groupnames=groupnames,
311
name='Object',
312
info='Selected Draw objects with id',
313
))
314
315
def activate_select(self, canvas=None):
316
"""
317
This call by metacanvas signals that the tool has been
318
activated and can now interact with metacanvas.
319
"""
320
BaseTool.activate(self, canvas)
321
self._idcounter = 0
322
323
def deactivate_select(self):
324
"""
325
This call by metacanvas signals that the tool has been
326
deactivated and can now interact with metacanvas.
327
"""
328
drawing = self._canvas.get_drawing()
329
330
if len(self) > 0:
331
# ungighlight selected objects
332
is_draw = False
333
for drawobj, _id in self.drawobjects.value: # drawing.get_drawobjs():
334
is_draw |= drawobj.unhighlight([_id], is_update=True)
335
if is_draw:
336
self._canvas.draw()
337
338
# remove selected objects
339
self.del_rows(self.get_ids())
340
341
BaseTool.deactivate(self)
342
343
def iterate_selection(self):
344
self.unhighlight_current()
345
self._idcounter += 1
346
if self._idcounter == len(self):
347
self._idcounter = 0
348
self.highlight_current()
349
350
def on_left_down_select(self, event):
351
# print 'on_left_down_select',len(self)>0,event.ShiftDown(),'is_show_selected',self.is_show_selected
352
is_draw = False
353
354
if len(self) > 0:
355
# print ' len(self)',len(self)
356
if event.ShiftDown():
357
# print ' ShiftDown'
358
self.iterate_selection()
359
self.on_change_selection(event)
360
is_draw = True
361
else:
362
# print ' on_execute_selection 1'
363
is_draw |= self.on_execute_selection(event)
364
is_draw |= self.unselect_all()
365
if self.is_show_selected:
366
self.parent.refresh_optionspanel(self)
367
368
else:
369
# print ' no selection len(self)',len(self)
370
is_draw |= self.pick_all(event)
371
self.highlight_current()
372
373
if not event.ShiftDown():
374
# print ' no shift down'
375
if self.is_preselected():
376
# print ' is_preselected len(self)',len(self)
377
self.coord_last = self._canvas.unproject(event.GetPosition())
378
# print ' on_execute_selection 2'
379
is_draw |= self.on_execute_selection(event)
380
# attention: on_execute_selection must take care of selected
381
# objects in list with self.unselect_all()
382
383
else:
384
# print ' shift down'
385
self.coord_last = self._canvas.unproject(event.GetPosition())
386
387
if self.is_show_selected:
388
# print ' is_show_selected',self.is_show_selected
389
self.parent.refresh_optionspanel(self)
390
391
return is_draw
392
393
def is_preselected(self):
394
"""
395
Check if there are preselected drawobjects in the list.
396
"""
397
return len(self) > 0
398
399
def on_execute_selection(self, event):
400
"""
401
Definively execute operation on currently selected drawobjects.
402
"""
403
self.set_objbrowser()
404
405
return False
406
407
def on_change_selection(self, event):
408
"""
409
Called after selection has been changed with SHIFT-click
410
Do operation on currently selected drawobjects.
411
"""
412
self.set_objbrowser()
413
return False
414
415
def set_objbrowser(self):
416
pass
417
418
def aboard_select(self, event):
419
# print 'aboard',self.ident
420
is_draw = self.unselect_all()
421
return is_draw
422
423
def get_current_selection(self):
424
if len(self) > 0:
425
(drawobj, _id) = self.drawobjects[self.get_ids()[self._idcounter]]
426
return drawobj, _id
427
else:
428
return None, -1
429
430
def is_tool_allowed_on_selection(self):
431
drawobj, _id = self.get_current_selection()
432
if drawobj is not None:
433
return drawobj.is_tool_allowed(self, _id)
434
else:
435
False
436
437
def pick_all(self, event):
438
"""
439
Pick all objets with id, that are near the pointer
440
coordinates.
441
"""
442
443
p = self._canvas.unproject_event(event)
444
445
if self.detectpix > 0:
446
# detect pixel sensitivity is given
447
# calculate detectwidth based on current resolution
448
self.detectwidth = self._canvas.get_resolution()*self.detectpix
449
450
print 'pick_all', self.detectwidth, self.detectpix, self._canvas.get_resolution()
451
452
self._idcounter = 0
453
is_draw = False
454
drawing = self._canvas.get_drawing()
455
# print ' ',drawing.get_drawobjs()
456
for drawobj in drawing.get_drawobjs():
457
if drawobj.is_visible():
458
ids_pick = drawobj.pick(p, detectwidth=self.detectwidth)
459
# print ' pick',drawobj.get_ident(),ids_pick
460
if len(ids_pick) > 0:
461
for id_pick in ids_pick:
462
is_draw |= self.add_selection(drawobj, id_pick, event)
463
464
return is_draw
465
466
def unhighlight_current(self):
467
# print 'unhighlight_current',len(self),self._idcounter
468
if len(self) > 0:
469
(drawobj, _id) = self.drawobjects[self.get_ids()[self._idcounter]]
470
drawobj.unhighlight([_id])
471
472
def highlight_current(self):
473
# print 'highlight_current',len(self),self._idcounter
474
if len(self) > 0:
475
(drawobj, _id) = self.drawobjects[self.get_ids()[self._idcounter]]
476
drawobj.highlight([_id])
477
478
def unselect_all(self):
479
# print 'unselect_all',len(self)
480
self._idcounter = 0
481
if len(self) > 0:
482
is_draw = True
483
for drawobj, _id in self.drawobjects.value:
484
if _id in drawobj:
485
drawobj.unhighlight([_id])
486
487
self.del_rows(self.get_ids())
488
else:
489
is_draw = False
490
491
if is_draw:
492
self.parent.refresh_optionspanel(self)
493
# print ' len should be 0:',len(self),is_draw
494
return is_draw
495
496
def add_selection(self, drawobj, id_pick, event=None):
497
is_draw = False
498
drawobjid = self.drawobjects.convert_type((drawobj, id_pick))
499
ids_match = self.select_ids(self.drawobjects.value == drawobjid)
500
if len(ids_match) == 0:
501
self.add_rows(1, drawobjects=[(drawobj, id_pick)])
502
is_draw = True
503
return is_draw
504
505
506
class AddLineTool(BaseTool):
507
"""
508
Mixin for Selection tools for OGL canvas.
509
"""
510
511
def __init__(self, parent, mainframe=None):
512
self.init_common('add_line', parent, 'Add line tool',
513
info='Click on canvas to add a line. Double click to finish, right click to aboard.',
514
is_textbutton=False,
515
)
516
self.init_options()
517
518
def init_options(self):
519
self.add(cm.AttrConf('width', 0.2,
520
groupnames=['options'],
521
perm='rw',
522
name='Width',
523
is_save=True,
524
info='Line width',
525
))
526
527
self.add(cm.AttrConf('color', np.array([1.0, 0.0, 0.0, 0.8], dtype=np.float32),
528
groupnames=['options'],
529
perm='rw',
530
metatype='color',
531
name='Fill color',
532
is_save=True,
533
info='Line color with format [r,g,b,a]',
534
))
535
536
# self.add(cm.AttrConf( 'color_fill', np.array([1.0,0.0,0.0,0.8], dtype=np.float32),
537
# groupnames = ['options'],
538
# perm='rw',
539
# metatype = 'color',
540
# name = 'Fill color',
541
# is_save = True,
542
# info = 'Object fill color with format [r,g,b,a]',
543
# ))
544
545
def set_button_info(self, bsize=(32, 32)):
546
# print 'set_button_info select tool'
547
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'line_24px.png'), wx.BITMAP_TYPE_PNG)
548
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'line_24px.png'), wx.BITMAP_TYPE_PNG)
549
550
def set_cursor(self):
551
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
552
if self._canvas is not None:
553
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
554
555
def activate(self, canvas=None):
556
"""
557
This call by metacanvas??TooldsPallet signals that the tool has been
558
activated and can now interact with metacanvas.
559
"""
560
# print 'activate',self.ident
561
self._is_active = True
562
self._canvas = canvas
563
# self._canvas.del_handles()
564
canvas.activate_tool(self)
565
self.set_cursor()
566
self.is_animated = False
567
568
def deactivate(self):
569
"""
570
This call by metacanvas??? ToolePallet signals that the tool has been
571
deactivated and can now interact with metacanvas.
572
"""
573
574
is_draw = self.aboard()
575
self._canvas.deactivate_tool()
576
self._canvas = None
577
self._is_active = False
578
return is_draw
579
580
def on_left_down(self, event):
581
if not self.is_animated:
582
return self.begin_animation(event)
583
584
def on_left_dclick(self, event):
585
if self.is_animated:
586
return self.end_animation(event)
587
588
def on_motion(self, event):
589
if self.is_animated:
590
return self.animate(event)
591
else:
592
return False
593
594
def begin_animation(self, event):
595
# print 'AddLineTool'
596
#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()
597
self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('fancylines')
598
self.coord_last = self._canvas.unproject(event.GetPosition())
599
vert = np.concatenate((self.coord_last, self.coord_last), 1).reshape((2, 3))
600
# print ' vert ',vert#,self.width.get_value(),self.color.get_value(),
601
_id = self.drawobj_anim.add_drawobj(vert,
602
self.width.get_value(), # width
603
self.color.get_value(),
604
beginstyle=TRIANGLEHEAD,
605
endstyle=TRIANGLEHEAD,
606
)
607
self.ind_vert = 1
608
self.drawobj_anim.begin_animation(_id)
609
610
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
611
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
612
self.is_animated = True
613
614
self.parent.refresh_optionspanel(self)
615
return True # True for redrawing
616
617
def end_animation(self, event):
618
self.drawobj_anim.end_animation(is_del_last_vert=False)
619
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
620
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
621
622
del self.drawobj_anim
623
#del self.id_anim
624
self.is_animated = False
625
self.parent.refresh_optionspanel(self)
626
return True # True for redrawing
627
628
def animate(self, event):
629
# print 'animate'
630
is_draw = False
631
coords = self._canvas.unproject(event.GetPosition())
632
vertex_delta = coords-self.coord_last
633
if np.any(np.abs(vertex_delta) > 0):
634
is_draw = self.drawobj_anim.stretch_animation(coords, vertex_delta, self.ind_vert)
635
if is_draw:
636
self.coord_last = coords
637
return is_draw
638
639
def aboard(self, event=None):
640
# print 'aboard',self.ident
641
642
is_draw = False
643
if self.is_animated:
644
#id_admin = self.drawobj_anim.get_id_admin()
645
self.drawobj_anim.del_animation(is_del_main=True)
646
del self.drawobj_anim
647
self.is_animated = False
648
is_draw = True
649
self.parent.refresh_optionspanel(self)
650
return is_draw # True for redrawing
651
652
# def set_objbrowser(self):
653
# pass
654
655
def get_optionspanel(self, parent, size=(200, -1)):
656
"""
657
Return tool option widgets on given parent
658
"""
659
if self.is_animated:
660
# show option of currently selected drawobj
661
self._optionspanel = ObjPanel(parent, obj=self.drawobj_anim,
662
id=self.drawobj_anim.get_id_anim(),
663
attrconfigs=None,
664
#tables = None,
665
# table = None, id=None, ids=None,
666
groupnames=['options'],
667
func_change_obj=None,
668
show_groupnames=False, show_title=True, is_modal=False,
669
mainframe=self.parent.get_mainframe(),
670
pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
671
func_apply=self.on_apply_option,
672
immediate_apply=False, panelstyle='default', # 'instrumental'
673
standartbuttons=['apply', 'restore'])
674
else:
675
676
self._optionspanel = ObjPanel(parent, obj=self,
677
id=None,
678
attrconfigs=None,
679
#tables = None,
680
# table = None, id=None, ids=None,
681
groupnames=['options'],
682
func_change_obj=None,
683
show_groupnames=False, show_title=True, is_modal=False,
684
mainframe=self.parent.get_mainframe(),
685
pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
686
func_apply=self.on_apply_option,
687
immediate_apply=False, panelstyle='default', # 'instrumental'
688
standartbuttons=['apply', 'restore'])
689
690
return self._optionspanel
691
692
def on_apply_option(self, drawobj, id, ids):
693
# print '\n\n\non_apply_option drawobj, id, ids',drawobj, id, ids
694
if self.is_animated:
695
if drawobj == self.drawobj_anim:
696
drawobj._update_colorvbo()
697
drawobj._update_vertexvbo()
698
699
self._canvas.draw()
700
701
702
class AddCircleTool(AddLineTool):
703
"""
704
Mixin for Selection tools for OGL canvas.
705
"""
706
707
def __init__(self, parent, mainframe=None):
708
self.init_common('add_circle', parent, 'Add circle tool',
709
info='Click on canvas to add a circle. Double click to finish, right click to aboard.',
710
is_textbutton=False,
711
)
712
self.init_options()
713
714
def init_options(self):
715
716
self.add(cm.AttrConf('color', np.array([1.0, 0.0, 0.0, 0.8], dtype=np.float32),
717
groupnames=['options'],
718
perm='rw',
719
metatype='color',
720
name='Color',
721
is_save=True,
722
info='Line color with format [r,g,b,a]',
723
))
724
725
self.add(cm.AttrConf('color_fill', np.array([1.0, 0.0, 0.0, 0.8], dtype=np.float32),
726
groupnames=['options'],
727
perm='rw',
728
metatype='color',
729
name='Fill color',
730
is_save=True,
731
info='Circle fill color with format [r,g,b,a]',
732
))
733
734
def set_button_info(self, bsize=(32, 32)):
735
# print 'set_button_info select tool'
736
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'circle_empty_24px.png'), wx.BITMAP_TYPE_PNG)
737
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'circle_empty_24px.png'), wx.BITMAP_TYPE_PNG)
738
739
def begin_animation(self, event):
740
# print 'AddLineTool'
741
#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()
742
self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('circles')
743
self.coord_last = self._canvas.unproject(event.GetPosition())
744
#vert = np.concatenate((self.coord_last,self.coord_last),1).reshape((2,3))
745
# print ' vert ',vert#,self.width.get_value(),self.color.get_value(),
746
747
_id = self.drawobj_anim.add_drawobj(1.0*self.coord_last,
748
0.0,
749
self.color.get_value(),
750
self.color_fill.get_value(),
751
)
752
753
self.drawobj_anim.begin_animation(_id)
754
755
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
756
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
757
self.is_animated = True
758
759
self.parent.refresh_optionspanel(self)
760
return True # True for redrawing
761
762
def end_animation(self, event):
763
self.drawobj_anim.end_animation(is_del_last_vert=False)
764
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
765
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
766
767
del self.drawobj_anim
768
#del self.id_anim
769
self.is_animated = False
770
self.parent.refresh_optionspanel(self)
771
return True # True for redrawing
772
773
def animate(self, event):
774
# print 'animate'
775
is_draw = False
776
coords = self._canvas.unproject(event.GetPosition())
777
vertex_delta = coords-self.coord_last
778
if np.any(np.abs(vertex_delta) > 0):
779
is_draw = self.drawobj_anim.stretch_animation(coords, vertex_delta, 1)
780
if is_draw:
781
self.coord_last = coords
782
return is_draw
783
784
785
class AddPolylineTool(AddLineTool):
786
"""
787
Mixin for Selection tools for OGL canvas.
788
"""
789
790
def __init__(self, parent, mainframe=None):
791
self.init_common('add_polyline', parent, 'Add polyline tool',
792
info='Click on canvas to add a poly line. Add a vertex with a single click, double click to finish, right click to aboard.',
793
is_textbutton=False,
794
)
795
self.init_options()
796
797
def set_button_info(self, bsize=(32, 32)):
798
# print 'set_button_info select tool'
799
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'polyline_24px.png'), wx.BITMAP_TYPE_PNG)
800
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'polyline_24px.png'), wx.BITMAP_TYPE_PNG)
801
802
def on_left_down(self, event):
803
if not self.is_animated:
804
return self.begin_animation(event)
805
else:
806
# add vertex
807
return self.append_vert_to_anim(event)
808
809
def begin_animation(self, event):
810
# print 'AddLineTool.begin_animation'
811
#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()
812
self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('polylines')
813
self.coord_last = self._canvas.unproject(event.GetPosition())
814
#vertices = [list(self.coord_last),list(self.coord_last) ]
815
vertices = [1.0*self.coord_last, 1.0*self.coord_last] # attention, we need copies here!!
816
# print ' vertices ',vertices#,self.width.get_value(),self.color.get_value(),
817
818
_id = self.drawobj_anim.add_drawobj(vertices,
819
self.width.get_value(), # width
820
self.color.get_value(),
821
beginstyle=TRIANGLEHEAD,
822
endstyle=TRIANGLEHEAD,
823
)
824
self.ind_vert = 1
825
self.drawobj_anim.begin_animation(_id)
826
827
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
828
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
829
self.is_animated = True
830
831
self.parent.refresh_optionspanel(self)
832
return True # True for redrawing
833
834
def end_animation(self, event):
835
self.drawobj_anim.end_animation(is_del_last_vert=True)
836
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
837
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
838
839
del self.drawobj_anim
840
#del self.id_anim
841
self.is_animated = False
842
self.parent.refresh_optionspanel(self)
843
return True # True for redrawing
844
845
def append_vert_to_anim(self, event):
846
self.coord_last = self._canvas.unproject(event.GetPosition())
847
848
self.ind_vert = self.drawobj_anim.append_vert_to_animation(self.coord_last)
849
850
return True
851
852
853
class AddPolygonTool(AddPolylineTool):
854
"""
855
Mixin for Selection tools for OGL canvas.
856
"""
857
858
def __init__(self, parent, mainframe=None):
859
self.init_common('add_polygon', parent, 'Add polygon tool',
860
info='Click on canvas to add a polygon. Add a vertex with a single click, double click to finish, right click to aboard.',
861
is_textbutton=False,
862
)
863
self.init_options()
864
865
def init_options(self):
866
self.add(cm.AttrConf('color', np.array([1.0, 0.0, 0.0, 0.8], dtype=np.float32),
867
groupnames=['options'],
868
perm='rw',
869
metatype='color',
870
name='Fill color',
871
is_save=True,
872
info='Line color with format [r,g,b,a]',
873
))
874
875
# self.add(cm.AttrConf( 'color_fill', np.array([1.0,0.0,0.0,0.8], dtype=np.float32),
876
# groupnames = ['options'],
877
# perm='rw',
878
# metatype = 'color',
879
# name = 'Fill color',
880
# is_save = True,
881
# info = 'Object fill color with format [r,g,b,a]',
882
# ))
883
884
def set_button_info(self, bsize=(32, 32)):
885
# print 'set_button_info select tool'
886
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'polygon2_24px.png'), wx.BITMAP_TYPE_PNG)
887
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'polygon2_24px.png'), wx.BITMAP_TYPE_PNG)
888
889
def begin_animation(self, event):
890
# print 'AddLineTool.begin_animation'
891
#self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()
892
self.drawobj_anim = self._canvas.get_drawing().get_drawobj_by_ident('polygons')
893
self.coord_last = self._canvas.unproject(event.GetPosition())
894
#vertices = [list(self.coord_last),list(self.coord_last) ]
895
vertices = [1.0*self.coord_last, 1.0*self.coord_last, ] # attention, we need copies here!!
896
# print ' vertices ',vertices#,self.width.get_value(),self.color.get_value(),
897
898
_id = self.drawobj_anim.add_drawobj(vertices,
899
color=self.color.get_value(),
900
)
901
self.ind_vert = 1
902
self.drawobj_anim.begin_animation(_id)
903
904
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
905
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
906
self.is_animated = True
907
908
self.parent.refresh_optionspanel(self)
909
return True # True for redrawing
910
911
912
class SelectTool(SelectToolMixin):
913
"""
914
Selection tool for OGL canvas.
915
"""
916
917
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
918
"""
919
To be overridden by specific tool.
920
"""
921
self.init_common('select', parent, 'Selection tool',
922
info='Select objects in canvas',
923
is_textbutton=False,
924
)
925
self._init_select(is_show_selected=True, detectwidth=detectwidth, detectpix=detectpix)
926
927
def set_button_info(self, bsize=(32, 32)):
928
# print 'set_button_info select tool' Select_32px
929
930
# wx.ART_INFORMATION
931
self._bitmap = wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, wx.ART_TOOLBAR)
932
self._bitmap_sel = wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, wx.ART_TOOLBAR)
933
934
#self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR,'Cursor-Click-icon_24px.png'),wx.BITMAP_TYPE_PNG)
935
# self._bitmap_sel=wx.Bitmap(os.path.join(IMAGEDIR,'Cursor-Click-icon_24px.png'),wx.BITMAP_TYPE_PNG)
936
937
#self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR,'selectIcon.bmp'),wx.BITMAP_TYPE_BMP)
938
# self._bitmap_sel=wx.Bitmap(os.path.join(IMAGEDIR,'selectIconSel.bmp'),wx.BITMAP_TYPE_BMP)
939
940
def set_cursor(self):
941
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
942
if self._canvas is not None:
943
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_QUESTION_ARROW))
944
945
def deactivate(self):
946
"""
947
This call by metacanvas signals that the tool has been
948
deactivated and can now interact with metacanvas.
949
"""
950
self.deactivate_select()
951
self._is_active = False
952
953
def activate(self, canvas=None):
954
"""
955
This call by metacanvas signals that the tool has been
956
activated and can now interact with metacanvas.
957
"""
958
self.activate_select(canvas) # calls also set_cursor
959
self._is_active = True
960
961
def on_left_down(self, event):
962
return self.on_left_down_select(event)
963
964
def aboard(self, event):
965
# print 'aboard',self.ident
966
return self.aboard_select(event)
967
968
969
class ConfigureTool(SelectToolMixin):
970
"""
971
Selection tool for OGL canvas.
972
"""
973
974
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
975
"""
976
To be overridden by specific tool.
977
"""
978
self.init_common('configure', parent, 'Configure tool',
979
info='Drawing options.',
980
is_textbutton=False,
981
)
982
983
self._init_select(is_show_selected=False, detectwidth=detectwidth, detectpix=detectpix)
984
985
# self.drawing =
986
#attrsman.add( cm.ObjConf( Nodes(self) ) )
987
988
# self.add_col(am.TabIdsArrayConf( 'drawobjects',
989
# groupnames = ['options'],
990
# name = 'Object',
991
# info = 'Selected Draw objects with id',
992
# ))
993
994
def set_button_info(self, bsize=(32, 32)):
995
# print 'set_button_info select tool'
996
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'gtk_configure_24px.png'), wx.BITMAP_TYPE_PNG)
997
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'gtk_configure_24px.png'), wx.BITMAP_TYPE_PNG)
998
999
def set_cursor(self):
1000
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1001
if self._canvas is not None:
1002
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_QUESTION_ARROW))
1003
1004
def deactivate(self):
1005
"""
1006
This call by metacanvas signals that the tool has been
1007
deactivated and can now interact with metacanvas.
1008
"""
1009
self.deactivate_select()
1010
self._is_active = False
1011
1012
def activate(self, canvas=None):
1013
"""
1014
This call by metacanvas signals that the tool has been
1015
activated and can now interact with metacanvas.
1016
"""
1017
self.activate_select(canvas) # calls also set_cursor
1018
self._is_active = True
1019
1020
def on_left_down(self, event):
1021
return self.on_left_down_select(event)
1022
1023
def aboard(self, event):
1024
# print 'aboard',self.ident
1025
return self.aboard_select(event)
1026
1027
def set_objbrowser(self):
1028
self.parent.refresh_optionspanel(self)
1029
1030
def get_optionspanel(self, parent):
1031
"""
1032
Return tool option widgets on given parent
1033
"""
1034
drawobj, _id = self.get_current_selection()
1035
if drawobj is None:
1036
# no current selection-> show options of whole drawing
1037
size = (200, -1)
1038
self._optionspanel = NaviPanel(parent, obj=self._canvas.get_drawing(),
1039
attrconfigs=None,
1040
#tables = None,
1041
# table = None, id=None, ids=None,
1042
groupnames=['options'],
1043
mainframe=self.parent.get_mainframe(),
1044
#pos=wx.DefaultPosition, size=size, style = wx.MAXIMIZE_BOX|wx.RESIZE_BORDER,
1045
func_apply=self.on_apply_option,
1046
immediate_apply=False, panelstyle='default', # 'instrumental'
1047
standartbuttons=['apply', 'restore'])
1048
else:
1049
# show option of currently selected drawobj
1050
size = (200, -1)
1051
self._optionspanel = ObjPanel(parent, obj=drawobj,
1052
id=_id,
1053
attrconfigs=None,
1054
#tables = None,
1055
# table = None, id=None, ids=None,
1056
groupnames=['options'],
1057
func_change_obj=None,
1058
show_groupnames=False, show_title=True, is_modal=False,
1059
mainframe=self.parent.get_mainframe(),
1060
pos=wx.DefaultPosition, size=size, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
1061
func_apply=self.on_apply_option,
1062
immediate_apply=False, panelstyle='default', # 'instrumental'
1063
standartbuttons=['apply', 'restore'])
1064
1065
return self._optionspanel
1066
1067
def on_apply_option(self, drawobj, id, ids):
1068
# print '\n\n\non_apply_option drawobj, id, ids',drawobj, id, ids
1069
drawing = self._canvas.get_drawing()
1070
drawobjs = drawing.get_drawobjs(is_anim=True)
1071
1072
if drawobj in drawobjs:
1073
drawobj._update_colorvbo()
1074
drawobj._update_vertexvbo()
1075
1076
self._canvas.draw()
1077
1078
1079
class HandleTool(SelectTool):
1080
"""
1081
General tool to help select handles.
1082
"""
1083
1084
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
1085
"""
1086
To be overridden by specific tool.
1087
"""
1088
self.init_common('select_handles', parent, 'Handle selection',
1089
info='Select handles on canvas',
1090
is_textbutton=False,
1091
)
1092
1093
self._init_select(detectwidth=detectwidth, detectpix=detectpix)
1094
1095
def _init_select(self, is_show_selected=True, detectwidth=0.1, detectpix=5):
1096
1097
SelectTool._init_select(self, is_show_selected, detectwidth=detectwidth, detectpix=detectpix)
1098
self.add_col(am.ArrayConf('inds_vertex', -1,
1099
groupnames=['options'], # ['_private_'], #'options',
1100
name='Vertex index',
1101
info='Vertex index.',
1102
))
1103
1104
def set_button_info(self, bsize=(32, 32)):
1105
# print 'set_button_info select tool' Select_32px
1106
1107
# wx.ART_INFORMATION
1108
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'Cursor-Click-icon_24px.png'), wx.BITMAP_TYPE_PNG)
1109
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'Cursor-Click-icon_24px.png'), wx.BITMAP_TYPE_PNG)
1110
1111
#self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR,'selectIcon.bmp'),wx.BITMAP_TYPE_BMP)
1112
# self._bitmap_sel=wx.Bitmap(os.path.join(IMAGEDIR,'selectIconSel.bmp'),wx.BITMAP_TYPE_BMP)
1113
1114
def set_cursor(self):
1115
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1116
if self._canvas is not None:
1117
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_RIGHT_ARROW))
1118
1119
def get_current_vertexselection(self):
1120
if len(self) > 0:
1121
id_selected = self.get_ids()[self._idcounter]
1122
(drawobj, _id) = self.drawobjects[id_selected]
1123
ind_vertex = self.inds_vertex[id_selected]
1124
return drawobj, _id, ind_vertex
1125
else:
1126
return None, -1, -1
1127
1128
def pick_all(self, event):
1129
"""
1130
Pick all objets with id and vertex index, that are near the pointer
1131
coordinates.
1132
"""
1133
# print 'HandleTool.pick_all'
1134
p = self._canvas.unproject_event(event)
1135
1136
if self.detectpix > 0:
1137
# detect pixel sensitivity is given
1138
# calculate detectwidth based on current resolution
1139
self.detectwidth = self._canvas.get_resolution()*self.detectpix
1140
1141
self._idcounter = 0
1142
is_draw = False
1143
drawing = self._canvas.get_drawing()
1144
# print ' ',drawing.get_drawobjs()
1145
for drawobj in drawing.get_drawobjs():
1146
# print ' ',drawobj,drawobj.get_ident()
1147
# experiment
1148
if drawobj.is_visible():
1149
handles = drawobj.pick_handle(p, detectwidth=self.detectwidth)
1150
# print ' handles',handles
1151
if len(handles) > 0:
1152
# print ' handles',drawobj.get_ident(),handles
1153
for id_handle, ind_vertex in handles:
1154
is_draw |= self.add_selection(drawobj, id_handle, ind_vertex, event)
1155
#is_draw |= self.select(drawobj,id_pick, event)
1156
# break
1157
return is_draw
1158
1159
def add_selection(self, drawobj, id_handle, ind_vertex, event):
1160
is_draw = False
1161
drawobjid = self.drawobjects.convert_type((drawobj, id_handle))
1162
ids_match = self.select_ids(self.drawobjects.value == drawobjid)
1163
if len(ids_match) == 0:
1164
self.add_rows(1, drawobjects=[(drawobj, id_handle)], inds_vertex=[ind_vertex])
1165
is_draw = True
1166
return is_draw
1167
1168
1169
class DeleteTool(SelectTool):
1170
"""
1171
Delete tool for OGL canvas.
1172
"""
1173
1174
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
1175
"""
1176
To be overridden by specific tool.
1177
"""
1178
self.init_common('delete', parent, 'Delete tool',
1179
info='Select and delete objects in canvas.',
1180
is_textbutton=False,
1181
)
1182
self._init_select(is_show_selected=True, detectwidth=detectwidth, detectpix=detectpix)
1183
1184
def set_button_info(self, bsize=(32, 32)):
1185
self._bitmap = wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR)
1186
self._bitmap_sel = wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_TOOLBAR)
1187
1188
def set_cursor(self):
1189
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1190
if self._canvas is not None:
1191
# self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_RIGHT_ARROW))
1192
pass
1193
1194
def on_execute_selection(self, event):
1195
"""
1196
Definively execute operation on currently selected drawobjects.
1197
"""
1198
if self.is_tool_allowed_on_selection():
1199
drawobj, _id = self.get_current_selection()
1200
1201
if drawobj is not None:
1202
drawobj.del_drawobj(_id)
1203
self.unselect_all()
1204
is_draw = True
1205
else:
1206
is_draw = False
1207
return is_draw
1208
else:
1209
return False
1210
1211
def on_change_selection(self, event):
1212
"""
1213
Called after selection has been changed with SHIFT-click
1214
Do operation on currently selected drawobjects.
1215
"""
1216
return False
1217
1218
1219
class MoveTool(SelectTool):
1220
"""
1221
Move tool for OGL canvas.
1222
"""
1223
1224
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
1225
"""
1226
To be overridden by specific tool.
1227
"""
1228
self.drawobj_anim, self.id_anim = (None, -1)
1229
1230
self.init_common('move', parent, 'Move tool',
1231
info='Select and drag objects in canvas.',
1232
is_textbutton=False,
1233
)
1234
self._init_select(is_show_selected=True, detectwidth=detectwidth, detectpix=detectpix)
1235
1236
def set_button_info(self, bsize=(32, 32)):
1237
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'arrow_cursor_drag_24px.png'), wx.BITMAP_TYPE_PNG)
1238
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'arrow_cursor_drag_24px.png'), wx.BITMAP_TYPE_PNG)
1239
1240
def activate(self, canvas=None):
1241
"""
1242
This call by metacanvas signals that the tool has been
1243
activated and can now interact with metacanvas.
1244
"""
1245
self.activate_select(canvas)
1246
self.is_animated = False
1247
self._is_active = True
1248
1249
def set_cursor(self):
1250
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1251
if self._canvas is not None:
1252
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
1253
1254
def deactivate(self):
1255
"""
1256
This call by metacanvas signals that the tool has been
1257
deactivated and can now interact with metacanvas.
1258
"""
1259
# self.deactivate_select()
1260
#self.is_animated = False
1261
is_draw = self.aboard()
1262
self._canvas.deactivate_tool()
1263
self._canvas = None
1264
self._is_active = False
1265
return is_draw
1266
1267
def on_left_down(self, event):
1268
if self.is_animated:
1269
return self.end_animation(event)
1270
else:
1271
return self.on_left_down_select(event)
1272
1273
def on_motion(self, event):
1274
if self.is_animated:
1275
return self.animate(event)
1276
else:
1277
return False
1278
1279
def on_execute_selection(self, event):
1280
"""
1281
Definively execute operation on currently selected drawobjects.
1282
"""
1283
if self.is_tool_allowed_on_selection():
1284
if not self.is_animated:
1285
return self.begin_animation(event)
1286
else:
1287
return self.end_animation(event)
1288
1289
else:
1290
return False
1291
1292
def on_change_selection(self, event):
1293
"""
1294
Called after selection has been changed with SHIFT-click
1295
Do operation on currently selected drawobjects.
1296
"""
1297
return False
1298
1299
def begin_animation(self, event):
1300
self.drawobj_anim, _id = self.get_current_selection()
1301
#self.drawobj_anim, self.id_anim = drawobj.get_anim(_id)
1302
self.drawobj_anim.begin_animation(_id)
1303
1304
# done in select method
1305
#self.coord_last = self._canvas.unproject(event.GetPosition())
1306
1307
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1308
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
1309
self.is_animated = True
1310
return True # True for redrawing
1311
1312
def end_animation(self, event):
1313
#drawobj, _id = self.get_current_selection()
1314
#drawobj.set_anim(_id, (self.drawobj_anim, self.id_anim))
1315
self.drawobj_anim.end_animation()
1316
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1317
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
1318
1319
del self.drawobj_anim
1320
#del self.id_anim
1321
self.is_animated = False
1322
1323
self.unselect_all()
1324
return True # True for redrawing
1325
1326
def animate(self, event):
1327
is_draw = False
1328
coords = self._canvas.unproject(event.GetPosition())
1329
vertex_delta = coords-self.coord_last
1330
if np.any(np.abs(vertex_delta) > 0):
1331
is_draw = self.drawobj_anim.move_animation(coords, vertex_delta)
1332
if is_draw:
1333
self.coord_last = coords
1334
return is_draw
1335
1336
def aboard(self, event=None):
1337
# print 'aboard',self.ident
1338
1339
is_draw = False
1340
if self.is_animated:
1341
self.drawobj_anim.del_animation()
1342
del self.drawobj_anim
1343
self.is_animated = False
1344
is_draw = True
1345
1346
is_draw |= self.aboard_select(event)
1347
return is_draw # True for redrawing
1348
1349
1350
class StretchTool(HandleTool):
1351
"""
1352
Stretch tool for OGL canvas.
1353
"""
1354
1355
def __init__(self, parent, detectwidth=0.1, detectpix=5, mainframe=None):
1356
"""
1357
To be overridden by specific tool.
1358
"""
1359
self.drawobj_anim, self.id_anim = (None, -1)
1360
1361
self.init_common('stretch', parent, 'Stretch tool',
1362
info='Select vertex and stretch object in canvas.',
1363
is_textbutton=False,
1364
)
1365
1366
self._init_select(is_show_selected=True, detectwidth=detectwidth, detectpix=detectpix)
1367
1368
def set_button_info(self, bsize=(32, 32)):
1369
# print 'set_button_info select tool' Select_32px
1370
1371
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'move_vertex_24px.png'), wx.BITMAP_TYPE_PNG)
1372
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'move_vertex_24px.png'), wx.BITMAP_TYPE_PNG)
1373
1374
# self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR,'Cursor-Click-icon_24px.png'),wx.BITMAP_TYPE_PNG)
1375
# self._bitmap_sel=wx.Bitmap(os.path.join(IMAGEDIR,'Cursor-Click-icon_24px.png'),wx.BITMAP_TYPE_PNG)
1376
1377
def set_cursor(self):
1378
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1379
if self._canvas is not None:
1380
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
1381
1382
def activate(self, canvas=None):
1383
"""
1384
This call by metacanvas signals that the tool has been
1385
activated and can now interact with metacanvas.
1386
"""
1387
self.activate_select(canvas)
1388
self.is_animated = False
1389
self._is_active = True
1390
1391
def deactivate(self):
1392
"""
1393
This call by metacanvas signals that the tool has been
1394
deactivated and can now interact with metacanvas.
1395
"""
1396
is_draw = self.aboard()
1397
self._canvas.deactivate_tool()
1398
self._canvas = None
1399
self._is_active = False
1400
return is_draw
1401
# self.deactivate_select()
1402
#self.is_animated = False
1403
1404
def on_left_down(self, event):
1405
if self.is_animated:
1406
return self.end_animation(event)
1407
else:
1408
# this call will set self.last_coord
1409
# and call self.on_execute_selection
1410
# in case a suitable object has been selected
1411
return self.on_left_down_select(event)
1412
1413
def on_motion(self, event):
1414
if self.is_animated:
1415
return self.animate(event)
1416
else:
1417
return False
1418
1419
def on_execute_selection(self, event):
1420
"""
1421
Definively execute operation on currently selected drawobjects.
1422
"""
1423
print 'Stretch', self.is_tool_allowed_on_selection()
1424
if self.is_tool_allowed_on_selection():
1425
if not self.is_animated:
1426
return self.begin_animation(event)
1427
else:
1428
return self.end_animation(event)
1429
else:
1430
return False
1431
1432
def on_change_selection(self, event):
1433
"""
1434
Called after selection has been changed with SHIFT-click
1435
Do operation on currently selected drawobjects.
1436
"""
1437
return False
1438
1439
def begin_animation(self, event):
1440
# print 'Stretchtool.begin_animation'
1441
self.drawobj_anim, _id, self.ind_vert = self.get_current_vertexselection()
1442
1443
# print ' self.drawobj_anim, _id, self.ind_vert=',self.drawobj_anim, _id, self.ind_vert
1444
#self.drawobj_anim, self.id_anim = drawobj.get_anim(_id)
1445
self.drawobj_anim.begin_animation(_id)
1446
self.coord_last = self._canvas.unproject(event.GetPosition())
1447
1448
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1449
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
1450
self.is_animated = True
1451
return True # True for redrawing
1452
1453
def end_animation(self, event):
1454
#drawobj, _id = self.get_current_selection()
1455
#drawobj.set_anim(_id, (self.drawobj_anim, self.id_anim))
1456
self.drawobj_anim.end_animation()
1457
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
1458
self._canvas.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
1459
1460
del self.drawobj_anim
1461
#del self.id_anim
1462
self.is_animated = False
1463
1464
self.unselect_all()
1465
return True # True for redrawing
1466
1467
def animate(self, event):
1468
# print 'animate'
1469
is_draw = False
1470
coords = self._canvas.unproject(event.GetPosition())
1471
vertex_delta = coords-self.coord_last
1472
if np.any(np.abs(vertex_delta) > 0):
1473
is_draw = self.drawobj_anim.stretch_animation(coords, vertex_delta, self.ind_vert)
1474
if is_draw:
1475
self.coord_last = coords
1476
return is_draw
1477
1478
def aboard(self, event=None):
1479
# print 'aboard',self.ident
1480
1481
is_draw = False
1482
if self.is_animated:
1483
self.drawobj_anim.del_animation()
1484
del self.drawobj_anim
1485
self.is_animated = False
1486
is_draw = True
1487
1488
is_draw |= self.aboard_select(event)
1489
return is_draw # True for redrawing
1490
1491
1492
class DrawobjMixin(am.ArrayObjman):
1493
def init_common(self, ident, parent=None, name=None,
1494
linewidth=1,
1495
is_parentobj=False,
1496
is_outline=True, # show outline
1497
is_fill=False,
1498
is_fillable=True,
1499
n_vert=2, # number of vertex per draw object
1500
c_highl=0.3, **kwargs):
1501
1502
self._init_objman(ident, parent=parent, name=name, **kwargs)
1503
1504
self._vbos = OrderedDict()
1505
1506
self._n_vert = n_vert
1507
1508
# ident of drawobject used for animations
1509
self._ident_drawobj_anim = 'anim_lines'
1510
1511
self.add(am.AttrConf('color_anim', np.array([0.9, 0.9, 0.9, 0.5], dtype=np.float32),
1512
groupnames=['_private_'],
1513
perm='rw',
1514
metatype='color',
1515
name='Anim. color',
1516
is_save=True,
1517
info='Color of animated object(s) in [r,g,b,a]',
1518
))
1519
1520
# TODO: these 2 could be eliminated and replaced by function
1521
# self._n_elem = 0# will be adjusted in update_vertexvbo
1522
#self._n_elem_fill = 0#
1523
1524
self.add(cm.AttrConf('_is_visible', True,
1525
groupnames=['options'],
1526
perm='wr',
1527
is_save=True,
1528
is_plugin=False,
1529
name='Visible?',
1530
info='If True, object are visible, otherwise it is not drwan.',
1531
))
1532
1533
if is_fillable > 0:
1534
# objects can potentially be filled
1535
self.add(cm.AttrConf('_is_fill', is_fill,
1536
groupnames=['_private'],
1537
perm='wr',
1538
is_save=True,
1539
is_plugin=False,
1540
name='Fill',
1541
info='If True, object are filled.',
1542
))
1543
self.add(cm.AttrConf('_is_outline', is_outline,
1544
groupnames=['_private'],
1545
perm='rw',
1546
is_save=True,
1547
is_plugin=False,
1548
name='Outline',
1549
info='If True, outline of object is shown.',
1550
))
1551
1552
self.add_col(am.ArrayConf('colors_fill', np.zeros(4, dtype=np.float32),
1553
dtype=np.float32,
1554
groupnames=['options'],
1555
perm='rw',
1556
metatype='color',
1557
name='Fill color',
1558
is_save=True,
1559
info='Object fill color with format [r,g,b,a]',
1560
))
1561
1562
self.add_col(am.ArrayConf('colors_fill_highl', np.zeros(4, dtype=np.float32),
1563
dtype=np.float32,
1564
groupnames=['_private'],
1565
perm='rw',
1566
metatype='color',
1567
name='Fill color highl',
1568
is_save=False,
1569
info='Object fill color when highlighting with format [r,g,b,a]',
1570
))
1571
1572
else:
1573
# no filling foreseen
1574
self.add(cm.AttrConf('_is_fill', False,
1575
groupnames=['_private'],
1576
perm='r',
1577
is_save=True,
1578
is_plugin=False,
1579
name='Filled',
1580
info='If True, object is filled.',
1581
))
1582
1583
self.add(cm.AttrConf('_is_outline', True,
1584
groupnames=['_private'],
1585
perm='r',
1586
is_save=True,
1587
is_plugin=False,
1588
name='Outline',
1589
info='If True, outline of object is shown.',
1590
))
1591
if is_outline:
1592
self.add_col(am.ArrayConf('colors', np.zeros(4, dtype=np.float32),
1593
dtype=np.float32,
1594
groupnames=['options'],
1595
perm='rw',
1596
metatype='color',
1597
name='Color',
1598
is_save=True,
1599
info='Object Vertex color with format [r,g,b,a]',
1600
))
1601
1602
self.add_col(am.ArrayConf('colors_highl', np.zeros(4, dtype=np.float32),
1603
dtype=np.float32,
1604
groupnames=['_private'],
1605
perm='rw',
1606
metatype='color',
1607
name='Color highl',
1608
is_save=False,
1609
info='Added object color when highlighting with format [r,g,b,a]',
1610
))
1611
1612
self.add(cm.AttrConf('linewidth', linewidth,
1613
groupnames=['options'],
1614
perm='wr',
1615
is_save=True,
1616
is_plugin=False,
1617
name='Line width',
1618
info='Line width in pixel',
1619
))
1620
1621
# print 'init_common',self.format_ident(),self._is_fill.value,self._is_outline.value
1622
1623
self.add(cm.AttrConf('c_highl', c_highl,
1624
groupnames=['_private'],
1625
perm='wr',
1626
is_save=True,
1627
is_plugin=False,
1628
name='Highl. const.',
1629
info='Highlight constant takes values beteewn 0 and 1 and is the amount of brightness added for highlighting',
1630
))
1631
1632
self.add_col(am.ArrayConf('are_highlighted', False,
1633
dtype=np.bool,
1634
groupnames=['options'],
1635
perm='rw',
1636
name='highlighted',
1637
is_save=False,
1638
info='If true, object is highlighted',
1639
))
1640
# self.add_col(am.ArrayConf( 'have_handles', False,
1641
# dtype=np.bool,
1642
# groupnames = ['options'],
1643
# perm='rw',
1644
# name = 'has handles',
1645
# is_save = False,
1646
# info = 'If true, object has handles',
1647
# ))
1648
1649
if is_parentobj:
1650
self.add_col(am.IdsArrayConf('ids_parent', parent,
1651
is_save=True,
1652
name=parent.format_ident()+'[ID]',
1653
info='ID of '+parent.get_name()+' object.',
1654
))
1655
1656
def get_vertices_array(self):
1657
return self.vertices.value
1658
1659
def get_vertices(self, ids):
1660
return self.vertices[ids]
1661
1662
def set_vertices(self, ids, vertices, is_update=True):
1663
self.vertices[ids] = vertices
1664
if is_update:
1665
self._update_vertexvbo()
1666
1667
def is_tool_allowed(self, tool, id_drawobj=-1):
1668
"""
1669
Returns True if this tool can be applied to this drawobj.
1670
Optionally a particular drawobj can be specified with id_drawobj.
1671
"""
1672
# basic tools:
1673
#tool.ident in 'configure','select_handles','delete','move','stretch'
1674
return True
1675
1676
def is_outline(self):
1677
return self._is_outline.get_value()
1678
1679
def is_fill(self):
1680
return self._is_fill.get_value()
1681
1682
def is_visible(self):
1683
return self._is_visible.value
1684
1685
def set_visible(self, is_visible):
1686
self._is_visible.set_value(is_visible)
1687
# print 'set_visible',self._is_visible.value
1688
1689
def del_drawobj(self, _id, is_update=True):
1690
self.del_row(_id)
1691
if is_update:
1692
self._update_vertexvbo()
1693
self._update_colorvbo()
1694
1695
def begin_animation(self, id_target):
1696
# print 'begin_animation',id_target
1697
# print ' self.vertices.value',self.vertices.value
1698
# print ' ids',self.get_ids()
1699
self._id_target = id_target
1700
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
1701
self.id_anim = self._drawobj_anim.add_drawobj(np.array(self.vertices[id_target]),
1702
self.color_anim.value,
1703
)
1704
return True
1705
1706
def end_animation(self, is_del_last_vert=False):
1707
# print 'end_animation',self.ident,self._id_target
1708
# print ' verices =',self._drawobj_anim.vertices[self.id_anim]
1709
self.set_vertices(self._id_target, self._drawobj_anim.get_vertices(self.id_anim)) # .copy()
1710
self.del_animation()
1711
# self._drawobj_anim.del_drawobj(self.id_anim)
1712
self._update_vertexvbo()
1713
self._update_colorvbo()
1714
return True
1715
1716
def del_animation(self, is_del_main=False):
1717
# print 'end_animation',self.ident,_id,self._drawobj_anim
1718
self._drawobj_anim.del_drawobj(self.id_anim)
1719
self._drawobj_anim = None
1720
1721
if is_del_main:
1722
self.del_drawobj(self._id_target)
1723
1724
self.id_anim = -1
1725
return True
1726
1727
def move_animation(self, vertex, vertex_delta):
1728
1729
# if self.ident == 'polylines':
1730
# print 'move_animation',self.ident,self._id_target, vertex_delta
1731
# print ' before self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim]
1732
# ans = self._drawobj_anim.move(self.id_anim, vertex, vertex_delta)
1733
# print ' after self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim]
1734
# return ans
1735
# else:
1736
return self._drawobj_anim.move(self.id_anim, vertex, vertex_delta)
1737
1738
def get_id_anim(self):
1739
return self._id_target
1740
1741
def stretch_animation(self, vertex, vertex_delta, ind_vertex):
1742
# print 'stretch',self.ident,_id
1743
# print ' ',vertex,vertex_delta,ind_vertex
1744
# if self.ident == 'polylines':
1745
# print 'stretch_animation',self.ident,self._id_target, ind_vertex, vertex_delta
1746
# print ' before self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim]
1747
# ans = self._drawobj_anim.stretch(self.id_anim,vertex, vertex_delta, ind_vertex)
1748
# print ' after self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim]
1749
# return ans
1750
# else:
1751
return self._drawobj_anim.stretch(self.id_anim, vertex, vertex_delta, ind_vertex)
1752
1753
def get_anim(self, _id):
1754
drawobj_anim = self.parent.get_drawobj_by_ident('anim_lines')
1755
1756
id_anim = drawobj_anim.add_drawobj(np.array(self.vertices[_id]),
1757
[0.9, 0.9, 0.9, 0.5]
1758
)
1759
# print 'get_anim',self.ident,_id,self.vertices[_id]
1760
return drawobj_anim, id_anim
1761
1762
def set_anim(self, _id, drawobjelem_anim):
1763
# print 'set_anim',self.ident,_id,drawobjelem_anim
1764
(drawobj_anim, id_anim) = drawobjelem_anim
1765
# print ' self.vertices[_id]=',self.vertices[_id]
1766
# print ' drawobj_anim.vertices[id_anim]=',drawobj_anim.vertices[id_anim]
1767
self.vertices[_id] = drawobj_anim.vertices[id_anim] # .copy()
1768
drawobj_anim.del_drawobj(id_anim)
1769
self._update_vertexvbo()
1770
return True
1771
1772
def move(self, _id, vertex, vertex_delta):
1773
# print 'move',self.ident,_id, vertex_delta
1774
self.vertices[_id] += vertex_delta
1775
# print ' vertices[id_anim]=',self.vertices[_id]
1776
self._update_vertexvbo()
1777
return True
1778
1779
def stretch(self, _id, vertex, vertex_delta, ind_vertex):
1780
# print 'stretch',self.ident,_id,ind_vertex
1781
# print ' vertex_delta',vertex_delta
1782
# print ' before vertices[_id]=',self.vertices[_id]
1783
self.vertices[_id][ind_vertex] += vertex_delta
1784
# print ' after vertices[_id]=',self.vertices[_id]
1785
self._update_vertexvbo()
1786
return True
1787
1788
def add_vbo(self, vbo):
1789
self._vbos[vbo.get_ident()] = vbo
1790
1791
def get_vbo(self, ident):
1792
return self._vbos[ident]
1793
1794
def get_vbos(self):
1795
return self._vbos.values()
1796
1797
def del_vbo(self, key):
1798
del self._vbos[key]
1799
1800
def get_n_vert(self):
1801
return self._n_vert
1802
1803
def _get_colors_highl(self, colors):
1804
return np.clip(colors+self.c_highl.value*np.ones(colors.shape, dtype=np.float32), 0, 1)-colors
1805
1806
def set_colors(self, ids, colors, colors_highl=None, is_update=True):
1807
self.colors[ids] = colors
1808
if colors_highl is None:
1809
self.colors_highl[ids] = self._get_colors_highl(colors)
1810
else:
1811
self.colors_highl[ids] = colors_highl
1812
if is_update:
1813
self._update_colorvbo()
1814
1815
def _update_colorvbo(self):
1816
n = len(self)
1817
if n == 0:
1818
for _vbo in self.get_vbos():
1819
_vbo.destroy()
1820
#n_vert = self.get_n_vert()
1821
# print '_update_colorvbo fancyline'
1822
1823
if self._is_outline.value:
1824
colors = self.colors.value + self.are_highlighted.value.reshape(n, 1)*self.colors_highl.value
1825
for _vbo in self.get_vbos():
1826
if not _vbo.is_fill():
1827
_vbo.update_colors(colors)
1828
1829
if self._is_fill.value:
1830
colors = self.colors_fill.value + self.are_highlighted.value.reshape(n, 1)*self.colors_fill_highl.value
1831
for _vbo in self.get_vbos():
1832
if _vbo.is_fill():
1833
_vbo.update_colors(colors)
1834
1835
def draw(self, resolution=1.0):
1836
# print 'draw n=',id(self),self.ident,len(self),self._is_visible.value
1837
if len(self) == 0:
1838
return
1839
if self._is_visible.value:
1840
glLineWidth(self.linewidth.value)
1841
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
1842
glEnable(GL_BLEND)
1843
1844
# main drawing
1845
glEnableClientState(GL_VERTEX_ARRAY)
1846
glEnableClientState(GL_COLOR_ARRAY)
1847
1848
# print 'draw',self.format_ident(), self._is_fill.value, self._is_outline.value
1849
1850
for _vbo in self.get_vbos():
1851
_vbo.draw(resolution)
1852
1853
# draw handles
1854
glDisableClientState(GL_VERTEX_ARRAY)
1855
glDisableClientState(GL_COLOR_ARRAY)
1856
1857
def highlight(self, ids, is_update=True):
1858
# print 'highlight=',ids
1859
# print ' inds',self._inds
1860
# print ' inds[ids]=',self._inds[ids]
1861
if len(ids) > 0:
1862
self.are_highlighted.value[self._inds[ids]] = True
1863
is_draw = True
1864
else:
1865
is_draw = False
1866
1867
if is_update:
1868
self._update_colorvbo()
1869
1870
return is_draw
1871
1872
def unhighlight(self, ids=None, is_update=True):
1873
1874
if ids is None:
1875
if np.any(self.are_highlighted.value):
1876
inds_highl = self._inds # np.flatnonzero(self.are_highlighted.value)
1877
self.are_highlighted.value[:] = False
1878
is_draw = True
1879
else:
1880
is_draw = False
1881
else:
1882
inds_highl = self._inds[ids]
1883
if np.any(self.are_highlighted.value[inds_highl]):
1884
self.are_highlighted.value[inds_highl] = False
1885
is_draw = True
1886
else:
1887
is_draw = False
1888
1889
# print 'unhighlight' , inds_highl
1890
# print ' self.are_highlighted.value',self.are_highlighted.value
1891
1892
if is_update:
1893
self._update_colorvbo()
1894
return is_draw
1895
1896
def pick_handle(self, coord):
1897
"""
1898
Retuns list [ id, ind_vert] when handle is near coord,
1899
otherwise []
1900
1901
"""
1902
return []
1903
1904
1905
class Lines(DrawobjMixin):
1906
def __init__(self, ident, parent, name='Lines',
1907
is_parentobj=False,
1908
n_vert=2, # 2 verts for line draw obj
1909
c_highl=0.3,
1910
linewidth=3,
1911
**kwargs):
1912
1913
self.init_common(ident, parent=parent, name=name,
1914
linewidth=linewidth,
1915
is_parentobj=is_parentobj,
1916
n_vert=n_vert,
1917
c_highl=c_highl,
1918
is_fillable=False,
1919
**kwargs)
1920
1921
# ident of drawobject used for animations
1922
# must be defined AFTER init_common
1923
self._ident_drawobj_anim = 'anim_lines'
1924
1925
self.add_vbo(Vbo('line', GL_LINES, 2, objtype='outline')) # 2 verts for OGL line element
1926
1927
self.add_col(am.ArrayConf('vertices', np.zeros((n_vert, 3), dtype=np.float32),
1928
dtype=np.float32,
1929
groupnames=['_private'],
1930
perm='rw',
1931
name='Vertex',
1932
unit='m',
1933
is_save=True,
1934
info='Vertex coordinate vectors of points. Example with 2 vertex: [[[x11,y11,z11],[x12,y12,z12]],[[x21,y21,z21],[x22,y22,z122]],...]',
1935
))
1936
1937
def get_boundingbox(self):
1938
if len(self) == 0:
1939
return None
1940
vv = self.get_vertices_array() # self.get_vertices.value
1941
# TODOD: can be done faster
1942
return np.array([[np.min(vv[:, :, 0]), np.min(vv[:, :, 1]), np.min(vv[:, :, 2])],
1943
[np.max(vv[:, :, 0]), np.max(vv[:, :, 1]), np.max(vv[:, :, 2])]
1944
], float)
1945
1946
def add_drawobj(self, vertices, color, color_highl=None, is_update=True):
1947
if color_highl is None:
1948
colors_highl = self._get_colors_highl(np.array([color]))
1949
1950
_id = self.add_row(vertices=vertices,
1951
colors=color,
1952
colors_highl=colors_highl[0],
1953
)
1954
if is_update:
1955
self._update_vertexvbo()
1956
self._update_colorvbo()
1957
return _id
1958
1959
def add_drawobjs(self, vertices, colors, colors_highl=None, is_update=True):
1960
if colors_highl is None:
1961
colors_highl = self._get_colors_highl(colors)
1962
1963
ids = self.add_rows(len(vertices),
1964
vertices=vertices,
1965
colors=colors,
1966
colors_highl=colors_highl,
1967
)
1968
if is_update:
1969
self._update_vertexvbo()
1970
self._update_colorvbo()
1971
return ids
1972
1973
def _update_vertexvbo(self):
1974
self.get_vbo('line').update_vertices(self.get_vertices_array().reshape((-1, 6)), len(self))
1975
1976
def _make_handlevbo(self, x, y, resolution):
1977
# print '_get_handlevbo'
1978
# print ' x =\n',x
1979
# print ' y =\n',y
1980
dx = resolution * 5.0
1981
dy = resolution * 5.0
1982
z = np.zeros(x.shape, dtype=np.float32)
1983
n = len(z)
1984
hvertices = np.concatenate((x-dx, y-dy, z, x+dx, y-dy, z, x+dx, y+dy, z, x-dx, y+dy, z, ), 1).reshape(-1, 4, 3)
1985
# print ' hvertices =\n',hvertices
1986
self._vertexvbo_handles = vbo.VBO(hvertices.reshape((-1, 3)))
1987
self._indexvbo_handles = vbo.VBO(np.arange(4*n, dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
1988
1989
colors = np.repeat(np.array([[0.9, 0.8, 0.7, 0.5]], dtype=np.float32), n, 0)
1990
self._colorvbo_handles = vbo.VBO(colors[np.array(np.arange(0, n, 1.0/4), int)])
1991
1992
def pick(self, p, detectwidth=0.1):
1993
"""
1994
Returns a binary vector which is True values for lines that have been selected
1995
by point p.
1996
1997
In particular, an element of this vector is True if the minimum distance
1998
between the respective line to point p is less than detectwidth
1999
"""
2000
# print 'pick',self.get_ident(),len(self)
2001
if len(self) == 0:
2002
return np.array([], np.int)
2003
2004
vertices = self.get_vertices_array()
2005
# print ' vertices',vertices
2006
x1 = vertices[:, 0, 0]
2007
y1 = vertices[:, 0, 1]
2008
2009
x2 = vertices[:, 1, 0]
2010
y2 = vertices[:, 1, 1]
2011
2012
return self._ids[get_dist_point_to_segs(p, x1, y1, x2, y2, is_ending=True) < detectwidth**2]
2013
2014
def pick_handle(self, coord, detectwidth=0.1):
2015
"""
2016
Retuns list [ id, ind_vert] when handle is near coord,
2017
otherwise []
2018
2019
"""
2020
# print 'pick_handle',self.get_ident(),len(self)
2021
dw = detectwidth**2
2022
2023
if len(self) == 0:
2024
return np.zeros((0, 2), np.int)
2025
2026
if self.ident not in ['lines', 'fancylines']:
2027
return np.zeros((0, 2), np.int)
2028
2029
vertices = self.get_vertices_array()
2030
handles = []
2031
# print ' vertices',vertices
2032
# print ' vertices.shape',vertices.shape
2033
dx = vertices[:, 0, 0]-coord[0]
2034
dy = vertices[:, 0, 1]-coord[1]
2035
2036
ids = self._ids[dx*dx+dy*dy < dw]
2037
handle1 = np.ones((len(ids), 2), np.int)
2038
handle1[:, 0] = ids
2039
handle1[:, 1] = 0
2040
# print ' ',d,handle1
2041
2042
dx = vertices[:, 1, 0]-coord[0]
2043
dy = vertices[:, 1, 1]-coord[1]
2044
ids = self._ids[dx*dx+dy*dy < dw]
2045
handle2 = np.ones((len(ids), 2), np.int)
2046
handle2[:, 0] = ids
2047
handle2[:, 1] = 1
2048
# print ' ',d,handle2
2049
handles = np.concatenate((handle1, handle2), 0)
2050
2051
return handles
2052
2053
def draw_old_handles(self, resolution=1.0):
2054
# print 'draw n=',len(self)
2055
glLineWidth(self.linewidth.value)
2056
2057
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
2058
glEnable(GL_BLEND)
2059
2060
# main drawing
2061
glEnableClientState(GL_VERTEX_ARRAY)
2062
glEnableClientState(GL_COLOR_ARRAY)
2063
2064
self._colorvbo.bind()
2065
glColorPointer(4, GL_FLOAT, 0, None)
2066
2067
self._vertexvbo.bind()
2068
self._indexvbo.bind()
2069
glVertexPointer(3, GL_FLOAT, 0, None)
2070
2071
glDrawElements(GL_LINES, self._n_vert*len(self), GL_UNSIGNED_INT, None)
2072
2073
glDisableClientState(GL_VERTEX_ARRAY)
2074
glDisableClientState(GL_COLOR_ARRAY)
2075
self._vertexvbo.unbind()
2076
self._indexvbo.unbind()
2077
self._colorvbo.unbind()
2078
2079
# draw handles
2080
if 1:
2081
vertices = self.vertices.value
2082
x1 = vertices[:, 0, 0]
2083
y1 = vertices[:, 0, 1]
2084
2085
x2 = vertices[:, 1, 0]
2086
y2 = vertices[:, 1, 1]
2087
self._make_handlevbo(x2.reshape(-1, 1), y2.reshape(-1, 1), resolution)
2088
2089
glLineWidth(2)
2090
glEnableClientState(GL_VERTEX_ARRAY)
2091
glEnableClientState(GL_COLOR_ARRAY)
2092
2093
self._colorvbo_handles.bind()
2094
glColorPointer(4, GL_FLOAT, 0, None)
2095
2096
self._vertexvbo_handles.bind()
2097
self._indexvbo_handles.bind()
2098
glVertexPointer(3, GL_FLOAT, 0, None)
2099
2100
# GL_LINE_STRIP, GL_QUADS, GL_LINES, GL_LINE_LOOP, GL_POINTS
2101
glDrawElements(GL_QUADS, 4*len(self), GL_UNSIGNED_INT, None)
2102
2103
glDisableClientState(GL_VERTEX_ARRAY)
2104
glDisableClientState(GL_COLOR_ARRAY)
2105
self._vertexvbo_handles.unbind()
2106
self._indexvbo_handles.unbind()
2107
self._colorvbo_handles.unbind()
2108
2109
2110
class Rectangles(Lines):
2111
def __init__(self, ident, parent, name='Rectangles',
2112
is_parentobj=False,
2113
is_fill=True,
2114
is_outline=True, # currently only fill implemented
2115
c_highl=0.3,
2116
linewidth=3,
2117
**kwargs):
2118
2119
self.init_common(ident, parent=parent, name=name,
2120
linewidth=linewidth, # for outline only
2121
is_parentobj=is_parentobj,
2122
is_fill=is_fill,
2123
is_outline=is_outline,
2124
n_vert=1, # vertex points for ending
2125
c_highl=c_highl,
2126
**kwargs)
2127
2128
# ident of drawobject used for animations
2129
# must be defined AFTER init_common
2130
self._ident_drawobj_anim = 'anim_rectangles'
2131
2132
# if is_outline:
2133
# self.add_vbo(Vbo('outline',GL_LINES,2, noncyclic = 0))
2134
2135
if is_fill:
2136
self.add_vbo(Vbo('rectangle_filled', GL_QUADS, 4, objtype='fill'))
2137
if is_outline:
2138
self.add_vbo(Vbo('rectangle_outline', GL_LINES, 2, objtype='outline'))
2139
2140
self.add_col(am.ArrayConf('offsets', np.zeros(3, dtype=np.float32),
2141
dtype=np.float32,
2142
groupnames=['_private'],
2143
perm='rw',
2144
name='Offset',
2145
unit='m',
2146
is_save=True,
2147
info='Offset of lower left corner',
2148
))
2149
2150
self.add_col(am.ArrayConf('widths', 0.5,
2151
dtype=np.float32,
2152
groupnames=['option'],
2153
perm='rw',
2154
name='Width',
2155
unit='m',
2156
is_save=True,
2157
info='Rectangle width',
2158
))
2159
2160
self.add_col(am.ArrayConf('lengths', 0.5,
2161
dtype=np.float32,
2162
groupnames=['option'],
2163
perm='rw',
2164
name='length',
2165
unit='m',
2166
is_save=True,
2167
info='Rectangle length',
2168
))
2169
2170
self.add_col(am.ArrayConf('rotangles_xy', 0.0,
2171
dtype=np.float32,
2172
groupnames=['option'],
2173
perm='rw',
2174
name='xy rot. angle',
2175
is_save=True,
2176
info='Counter clockwise rotation angle in xy plane',
2177
))
2178
2179
def add_drawobj(self, offset, width, length, rotangle_xy,
2180
color, color_fill=None,
2181
color_highl=None, color_fill_highl=None,
2182
is_update=True):
2183
# print 'Fancylines.add_drawobj'
2184
if color_highl is None:
2185
color_highl = self._get_colors_highl(np.array([color]))[0]
2186
2187
if color_fill is None:
2188
color_fill = color
2189
2190
if color_fill_highl is None:
2191
color_fill_highl = self._get_colors_highl(np.array([color_fill]))[0]
2192
2193
# print ' ids',self.get_ids()
2194
_id = self.add_row(offsets=offset,
2195
widths=width,
2196
lengths=length,
2197
rotangles_xy=rotangle_xy,
2198
colors=color,
2199
colors_highl=color_highl,
2200
colors_fill=color_fill,
2201
colors_fill_highl=color_fill_highl,
2202
)
2203
if is_update:
2204
self._update_vertexvbo()
2205
self._update_colorvbo()
2206
return _id
2207
2208
def add_drawobjs(self, offsets, widths, lengths, rotangles_xy,
2209
colors, colors_fill=None,
2210
colors_highl=None, colors_fill_highl=None,
2211
is_update=True):
2212
# print 'add_drawobjs'
2213
if colors_highl is None:
2214
colors_highl = self._get_colors_highl(colors)
2215
2216
n = len(offsets)
2217
if colors_fill_highl is None:
2218
colors_fill_highl = self._get_colors_highl(colors_fill)
2219
ids = self.add_rows(n,
2220
offsets=offsets,
2221
widths=widths,
2222
lengths=lengths,
2223
rotangles_xy=rotangles_xy,
2224
colors=colors,
2225
colors_highl=colors_highl,
2226
colors_fill=colors_fill,
2227
colors_fill_highl=colors_fill_highl,
2228
)
2229
# self.print_attrs()
2230
if is_update:
2231
self._update_vertexvbo()
2232
self._update_colorvbo()
2233
return ids
2234
2235
def begin_animation(self, id_target):
2236
2237
self._id_target = id_target
2238
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
2239
self.id_anim = self._drawobj_anim.add_drawobj(1.0*self.offsets[id_target],
2240
1.0*self.widths[id_target],
2241
1.0*self.lengths[id_target],
2242
1.0*self.rotangles_xy[id_target],
2243
color=self.color_anim.value,
2244
)
2245
# print 'begin_animation',self.ident,_id,self._drawobj_anim
2246
return True
2247
2248
def end_animation(self, is_del_last_vert=False):
2249
# print 'end_animation',self.ident,self._id_target
2250
# print ' verices =',self._drawobj_anim.vertices[self.id_anim]
2251
self.set_offsets(self._id_target, self._drawobj_anim.get_offsets(self.id_anim)) # .copy()
2252
self.del_animation()
2253
# self._drawobj_anim.del_drawobj(self.id_anim)
2254
self._update_vertexvbo()
2255
self._update_colorvbo()
2256
return True
2257
2258
def set_anim(self, _id, drawobjelem_anim):
2259
# print 'set_anim',self.ident,_id,drawobjelem_anim
2260
(drawobj_anim, id_anim) = drawobjelem_anim
2261
# print ' self.vertices[_id]=',self.vertices[_id]
2262
# print ' drawobj_anim.vertices[id_anim]=',drawobj_anim.vertices[id_anim]
2263
self.vertices[_id] = drawobj_anim.vertices[id_anim] # .copy()
2264
drawobj_anim.del_drawobj(id_anim)
2265
self._update_vertexvbo()
2266
return True
2267
2268
def move(self, _id, vertex, vertex_delta):
2269
# print 'move',self.ident,_id, vertex_delta
2270
self.offsets[_id] += vertex_delta
2271
# print ' vertices[id_anim]=',self.vertices[_id]
2272
self._update_vertexvbo()
2273
return True
2274
2275
def stretch(self, _id, vertex, vertex_delta, ind_vertex):
2276
# print 'stretch',self.ident,_id,ind_vertex
2277
# print ' vertex_delta',vertex_delta
2278
# print ' before vertices[_id]=',self.vertices[_id]
2279
#self.vertices[_id][ind_vertex] += vertex_delta
2280
# print ' after vertices[_id]=',self.vertices[_id]
2281
self._update_vertexvbo()
2282
return True
2283
2284
def get_offsets_array(self):
2285
return self.offsets.value
2286
2287
def get_offsets(self, ids):
2288
return self.offsets[ids]
2289
2290
def set_offsets(self, ids, values):
2291
self.offsets[ids] = values
2292
2293
def get_widths_array(self):
2294
return self.widths.value
2295
2296
def get_widths(self, ids):
2297
return self.widths[ids]
2298
2299
def set_widths(self, ids, values):
2300
self.widths[ids] = values
2301
2302
def get_lengths_array(self):
2303
return self.lengths.value
2304
2305
def get_lengths(self, ids):
2306
return self.lengths[ids]
2307
2308
def set_lengths(self, ids, values):
2309
self.lengths[ids] = values
2310
2311
def get_rotangles_xy_array(self):
2312
return self.rotangles_xy.value
2313
2314
def get_rotangles_xy(self, ids):
2315
return self.rotangles_xy[ids]
2316
2317
def set_rotangles_xy(self, ids, values):
2318
self.rotangles_xy[ids] = values
2319
2320
def _update_vertexvbo(self):
2321
# print '_update_vertexvbo',self.format_ident()
2322
self._make_lines()
2323
n = len(self)
2324
if self.is_fill():
2325
self.get_vbo('rectangle_filled').update_vertices(self._vertices, n)
2326
if self.is_outline():
2327
self.get_vbo('rectangle_outline').update_vertices(self._linevertices, n)
2328
2329
def _make_lines(self):
2330
# print '_make_lines'
2331
2332
vertices = self.get_vertices_array()
2333
2334
n = len(self)
2335
n_lpe = 4 # lines per element (here 4 lines for a rectangle)
2336
n_lines_tot = n*n_lpe
2337
2338
linevertices = np.zeros((n, 2*n_lpe, 3), np.float32)
2339
2340
# fix first and last point of each rectangle
2341
linevertices[:, 0, :] = vertices[:, 0, :]
2342
linevertices[:, -1, :] = vertices[:, 0, :]
2343
# do rest of the vertices by doubling orginal
2344
linevertices[:, 1:-1, :] = np.repeat(vertices[:, 1:, :], 2, 1)
2345
# print ' linevertices\n',linevertices
2346
2347
#vertexinds = np.zeros((n_lines_tot,2),np.int32)
2348
inds = self.get_inds()
2349
vertexinds = np.repeat(inds, 2*n_lpe).reshape((n_lines_tot, 2))
2350
# print ' vertexinds\n',vertexinds
2351
#rectinds = np.zeros(n_lines_tot,np.int32)
2352
rectinds = np.repeat(inds, n_lpe)
2353
2354
self._vertices = vertices
2355
self._linevertices = linevertices.reshape((2*n_lines_tot, 3))
2356
# print ' self._linevertices',self._linevertices
2357
self._rectinds = rectinds
2358
self._vertexinds = vertexinds
2359
2360
def get_vertices_array(self):
2361
# print 'Rectangles.get_vertices_array'
2362
n = len(self)
2363
offsets = self.get_offsets_array()
2364
widths = self.get_widths_array()
2365
lengths = self.get_lengths_array()
2366
alphas = self.get_rotangles_xy_array()
2367
# print 'widths',widths
2368
# print 'lengths',lengths
2369
# print ' alphas',alphas
2370
sin_alphas = np.sin(alphas)
2371
cos_alphas = np.cos(alphas)
2372
2373
zeros = np.zeros(n, np.float32)
2374
vertices = np.zeros((n, 4, 3), np.float32)
2375
2376
vertices[:, 0, :] = offsets
2377
vertices[:, 1, :] = offsets
2378
vertices_rot = rotate_vertices(widths, zeros,
2379
sin_alphas=sin_alphas,
2380
cos_alphas=cos_alphas,
2381
is_array=True,
2382
)
2383
2384
# print ' vertices_rot = ',vertices_rot.shape,vertices_rot,
2385
vertices[:, 1, :2] += rotate_vertices(widths, zeros,
2386
sin_alphas=sin_alphas,
2387
cos_alphas=cos_alphas,
2388
is_array=True,
2389
)
2390
2391
vertices[:, 2, :] = offsets
2392
vertices[:, 2, :2] += rotate_vertices(widths, lengths,
2393
sin_alphas=sin_alphas,
2394
cos_alphas=cos_alphas,
2395
is_array=True,
2396
)
2397
2398
vertices[:, 3, :] = offsets
2399
vertices[:, 3, :2] += rotate_vertices(zeros, lengths,
2400
sin_alphas=sin_alphas,
2401
cos_alphas=cos_alphas,
2402
is_array=True,
2403
)
2404
2405
return vertices
2406
2407
def pick(self, p, detectwidth=0.1):
2408
"""
2409
Returns a binary vector which is True values for lines that have been selected
2410
by point p.
2411
2412
"""
2413
# print 'pick'
2414
if len(self) == 0:
2415
return np.array([], np.int)
2416
2417
vertices = self.get_vertices_array()
2418
# print ' vertices.shape',vertices.shape,'\n',vertices
2419
inds1 = is_inside_triangles(p, vertices[:, 0, 0], vertices[:, 0, 1],
2420
vertices[:, 1, 0], vertices[:, 1, 1],
2421
vertices[:, 2, 0], vertices[:, 2, 1])
2422
2423
inds2 = is_inside_triangles(p, vertices[:, 0, 0], vertices[:, 0, 1],
2424
vertices[:, 2, 0], vertices[:, 2, 1],
2425
vertices[:, 3, 0], vertices[:, 3, 1])
2426
2427
return self._ids[np.flatnonzero(inds1 | inds2)]
2428
2429
2430
class Triangles(Lines):
2431
def __init__(self, ident, parent, name='Triangles',
2432
is_parentobj=False,
2433
is_fill=True,
2434
is_outline=True, # currently only fill implemented
2435
c_highl=0.3,
2436
linewidth=3,
2437
**kwargs):
2438
2439
n_vert = 3 # 3 verts for triangle draw obj
2440
self.init_common(ident, parent=parent, name=name,
2441
linewidth=linewidth, # for outline only
2442
is_parentobj=is_parentobj,
2443
is_fill=is_fill,
2444
is_outline=is_outline,
2445
n_vert=n_vert,
2446
c_highl=c_highl,
2447
**kwargs)
2448
2449
# ident of drawobject used for animations
2450
# must be defined AFTER init_common
2451
self._ident_drawobj_anim = 'anim_triangles'
2452
2453
# if is_outline:
2454
# self.add_vbo(Vbo('outline',GL_LINES,2, noncyclic = 0))
2455
2456
if is_fill:
2457
self.add_vbo(Vbo('triangle_filled', GL_TRIANGLES, 3, objtype='fill'))
2458
if is_outline:
2459
self.add_vbo(Vbo('triangle_outline', GL_LINES, 2, objtype='outline'))
2460
2461
self.add_col(am.ArrayConf('vertices', np.zeros((n_vert, 3), dtype=np.float32),
2462
dtype=np.float32,
2463
groupnames=['_private'],
2464
perm='rw',
2465
name='Vertex',
2466
unit='m',
2467
is_save=True,
2468
info='Triangle vertex coordinate vectors of points: [[[x11,y11,z11],[x12,y12,z12],[x13,y13,z13]],[[x21,y21,z21],[x22,y22,z122],[x13,y13,z13]],...]',
2469
))
2470
2471
def add_drawobj(self, vertex,
2472
color, color_fill=None,
2473
color_highl=None, color_fill_highl=None,
2474
is_update=True):
2475
# print 'Fancylines.add_drawobj'
2476
if color_highl is None:
2477
color_highl = self._get_colors_highl(np.array([color]))[0]
2478
2479
if color_fill is None:
2480
color_fill = color
2481
2482
if color_fill_highl is None:
2483
color_fill_highl = self._get_colors_highl(np.array([color_fill]))[0]
2484
2485
# print ' ids',self.get_ids()
2486
_id = self.add_row(vertices=vertex,
2487
colors=color,
2488
colors_highl=color_highl,
2489
colors_fill=color_fill,
2490
colors_fill_highl=color_fill_highl,
2491
)
2492
if is_update:
2493
self._update_vertexvbo()
2494
self._update_colorvbo()
2495
return _id
2496
2497
def add_drawobjs(self, vertices,
2498
colors, colors_fill=None,
2499
colors_highl=None, colors_fill_highl=None,
2500
is_update=True):
2501
# print 'add_drawobjs'
2502
if colors_highl is None:
2503
colors_highl = self._get_colors_highl(colors)
2504
2505
n = len(vertices)
2506
if colors_fill_highl is None:
2507
colors_fill_highl = self._get_colors_highl(colors_fill)
2508
ids = self.add_rows(n,
2509
vertices=vertices,
2510
colors=colors,
2511
colors_highl=colors_highl,
2512
colors_fill=colors_fill,
2513
colors_fill_highl=colors_fill_highl,
2514
)
2515
# self.print_attrs()
2516
if is_update:
2517
self._update_vertexvbo()
2518
self._update_colorvbo()
2519
return ids
2520
2521
def _update_vertexvbo(self):
2522
if self.is_fill():
2523
self.get_vbo('triangle_filled').update_vertices(self.get_vertices_array().reshape((-1, 3*3)), len(self))
2524
if self.is_outline():
2525
self.get_vbo('triangle_outline').update_vertices(self._get_linevertices(), len(self))
2526
2527
def _get_linevertices(self):
2528
# print '_make_lines'
2529
2530
vertices = self.get_vertices_array()
2531
2532
n = len(self)
2533
n_lpe = 3 # lines per element (here 4 lines for a rectangle)
2534
n_lines_tot = n*n_lpe
2535
2536
linevertices = np.zeros((n, 2*n_lpe, 3), np.float32)
2537
2538
# fix first and last point of each rectangle
2539
linevertices[:, 0, :] = vertices[:, 0, :]
2540
linevertices[:, -1, :] = vertices[:, 0, :]
2541
# do rest of the vertices by doubling orginal
2542
linevertices[:, 1:-1, :] = np.repeat(vertices[:, 1:, :], 2, 1)
2543
# print ' linevertices\n',linevertices
2544
2545
#vertexinds = np.zeros((n_lines_tot,2),np.int32)
2546
#inds = self.get_inds()
2547
#vertexinds = np.repeat(inds,2*n_lpe).reshape((n_lines_tot,2))
2548
# print ' vertexinds\n',vertexinds
2549
#rectinds = np.zeros(n_lines_tot,np.int32)
2550
#rectinds = np.repeat(inds,n_lpe)
2551
2552
#self._vertices = vertices
2553
return linevertices.reshape((2*n_lines_tot, 3))
2554
# print ' self._linevertices',self._linevertices
2555
#self._rectinds = rectinds
2556
#self._vertexinds = vertexinds
2557
2558
def pick(self, p, detectwidth=0.1):
2559
"""
2560
Returns a binary vector which is True values for lines that have been selected
2561
by point p.
2562
2563
"""
2564
# print 'pick'
2565
if len(self) == 0:
2566
return np.array([], np.int)
2567
2568
vertices = self.get_vertices_array()
2569
# print ' vertices.shape',vertices.shape,'\n',vertices
2570
inds = is_inside_triangles(p, vertices[:, 0, 0], vertices[:, 0, 1],
2571
vertices[:, 1, 0], vertices[:, 1, 1],
2572
vertices[:, 2, 0], vertices[:, 2, 1])
2573
2574
return self._ids[np.flatnonzero(inds)]
2575
2576
def pick_handle(self, coord, detectwidth=0.1):
2577
"""
2578
Retuns list [ id, ind_vert] when handle is near coord,
2579
otherwise []
2580
2581
"""
2582
# print 'Triangles.pick_handle',self.get_ident(),len(self)
2583
dw = detectwidth**2
2584
2585
if len(self) == 0:
2586
return np.zeros((0, 2), np.int)
2587
2588
vertices = self.get_vertices_array()
2589
handles = []
2590
# print ' vertices',vertices
2591
# print ' vertices.shape',vertices.shape
2592
dx = vertices[:, 0, 0]-coord[0]
2593
dy = vertices[:, 0, 1]-coord[1]
2594
2595
ids = self._ids[dx*dx+dy*dy < dw]
2596
handle1 = np.ones((len(ids), 2), np.int)
2597
handle1[:, 0] = ids
2598
handle1[:, 1] = 0
2599
# print ' ',d,handle1
2600
2601
dx = vertices[:, 1, 0]-coord[0]
2602
dy = vertices[:, 1, 1]-coord[1]
2603
ids = self._ids[dx*dx+dy*dy < dw]
2604
handle2 = np.ones((len(ids), 2), np.int)
2605
handle2[:, 0] = ids
2606
handle2[:, 1] = 1
2607
2608
dx = vertices[:, 2, 0]-coord[0]
2609
dy = vertices[:, 2, 1]-coord[1]
2610
ids = self._ids[dx*dx+dy*dy < dw]
2611
handle3 = np.ones((len(ids), 2), np.int)
2612
handle3[:, 0] = ids
2613
handle3[:, 1] = 2
2614
2615
# print ' ',d,handle2
2616
handles = np.concatenate((handle1, handle2, handle3), 0)
2617
2618
return handles
2619
2620
2621
class Fancylines(Lines):
2622
def __init__(self, ident, parent, name='Fancy lines',
2623
is_parentobj=False,
2624
is_fill=True,
2625
is_outline=False, # currently only fill implemented
2626
arrowstretch=2.5,
2627
arrowlength=0.5,
2628
is_lefthalf=True,
2629
is_righthalf=True,
2630
c_highl=0.3,
2631
linewidth=3,
2632
**kwargs):
2633
2634
self.init_common(ident, parent=parent, name=name,
2635
linewidth=linewidth, # for outline only
2636
is_parentobj=is_parentobj,
2637
is_fill=is_fill,
2638
is_outline=is_outline,
2639
n_vert=3, # vertex points for ending
2640
c_highl=c_highl,
2641
**kwargs)
2642
2643
# ident of drawobject used for animations
2644
# must be defined AFTER init_common
2645
self._ident_drawobj_anim = 'anim_fancylines'
2646
2647
# if is_outline:
2648
# self.add_vbo(Vbo('outline',GL_LINES,2, noncyclic = 0))
2649
2650
if is_fill:
2651
self.add_vbo(Vbo('line_fill', GL_QUADS, 4, objtype='fill'))
2652
for style in LINEHEADS.keys():
2653
self.add_vbo(Vbo(('begin', 'fill', style), GL_TRIANGLES, 3, objtype='fill'))
2654
self.add_vbo(Vbo(('end', 'fill', style), GL_TRIANGLES, 3, objtype='fill'))
2655
2656
self.add(cm.AttrConf('arrowstretch', arrowstretch,
2657
groupnames=['options'],
2658
perm='wr',
2659
is_save=True,
2660
is_plugin=False,
2661
name='Arrow stretch',
2662
info='Arrow stretch factor.',
2663
))
2664
2665
# self.add(cm.AttrConf( 'arrowlength', arrowlength,
2666
# groupnames = ['options'],
2667
# perm='wr',
2668
# is_save = True,
2669
# is_plugin = False,
2670
# name = 'Arrow length',
2671
# info = 'Arrow length.',
2672
# ))
2673
2674
self.add(cm.AttrConf('is_lefthalf', is_lefthalf,
2675
groupnames=['options'],
2676
perm='wr',
2677
is_save=True,
2678
is_plugin=False,
2679
name='Show left',
2680
info='Show left half of line.',
2681
))
2682
2683
self.add(cm.AttrConf('is_righthalf', is_righthalf,
2684
groupnames=['options'],
2685
perm='wr',
2686
is_save=True,
2687
is_plugin=False,
2688
name='Show right',
2689
info='Show right half of line.',
2690
))
2691
2692
self.add_col(am.ArrayConf('beginstyles', 0,
2693
groupnames=['options'],
2694
perm='rw',
2695
choices=LINEHEADS,
2696
is_save=True,
2697
is_plugin=False,
2698
name='Begin style',
2699
info='Style of the line extremity at the beginning.',
2700
))
2701
2702
self.add_col(am.ArrayConf('endstyles', 0,
2703
groupnames=['options'],
2704
perm='rw',
2705
choices=LINEHEADS,
2706
is_save=True,
2707
is_plugin=False,
2708
name='End style',
2709
info='Style of the line extremity at the ending.',
2710
))
2711
2712
self.add_col(am.ArrayConf('vertices', np.zeros((2, 3), dtype=np.float32),
2713
dtype=np.float32,
2714
groupnames=['_private'],
2715
perm='rw',
2716
name='Vertex',
2717
unit='m',
2718
is_save=True,
2719
info='Vertex coordinate vectors of points. Example with 2 vertex: [[[x11,y11,z11],[x12,y12,z12]],[[x21,y21,z21],[x22,y22,z122]],...]',
2720
))
2721
2722
self.add_col(am.ArrayConf('widths', 0.5,
2723
dtype=np.float32,
2724
groupnames=['option'],
2725
perm='rw',
2726
name='Width',
2727
unit='m',
2728
is_save=True,
2729
info='Line width',
2730
))
2731
2732
def add_drawobj(self, vertices, width, color, color_highl=None,
2733
beginstyle=None,
2734
endstyle=None,
2735
is_update=True):
2736
# print 'Fancylines.add_drawobj'
2737
if color_highl is None:
2738
color_highl = self._get_colors_highl(np.array([color]))[0]
2739
2740
# print ' ids',self.get_ids()
2741
_id = self.add_row(vertices=vertices,
2742
widths=width,
2743
colors=color,
2744
colors_highl=color_highl,
2745
colors_fill=color,
2746
colors_fill_highl=color_highl,
2747
beginstyles=beginstyle,
2748
endstyles=endstyle,
2749
2750
)
2751
if is_update:
2752
self._update_vertexvbo()
2753
self._update_colorvbo()
2754
return _id
2755
2756
def add_drawobjs(self, vertices, widths, colors, colors_highl=None,
2757
beginstyles=None, endstyles=None,
2758
is_update=True):
2759
2760
if colors_highl is None:
2761
colors_highl = self._get_colors_highl(colors)
2762
2763
n = len(vertices)
2764
if beginstyles is None:
2765
beginstyles = np.zeros(n)
2766
if endstyles is None:
2767
endstyles = np.zeros(n)
2768
ids = self.add_rows(len(vertices),
2769
vertices=vertices,
2770
widths=widths,
2771
colors=colors,
2772
colors_highl=colors_highl,
2773
colors_fill=colors,
2774
colors_fill_highl=colors_highl,
2775
beginstyles=beginstyles,
2776
endstyles=endstyles,
2777
)
2778
if is_update:
2779
self._update_vertexvbo()
2780
self._update_colorvbo()
2781
return ids
2782
2783
def begin_animation(self, id_target):
2784
2785
self._id_target = id_target
2786
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
2787
self.id_anim = self._drawobj_anim.add_drawobj(np.array(self.get_vertices(id_target)),
2788
1.0*self.get_widths(id_target),
2789
self.color_anim.value,
2790
beginstyle=self.beginstyles[id_target],
2791
endstyle=self.endstyles[id_target],
2792
)
2793
# print 'begin_animation',self.ident,_id,self._drawobj_anim
2794
return True
2795
2796
def get_widths_array(self):
2797
return self.widths.value
2798
2799
def get_widths(self, ids):
2800
return self.widths[ids]
2801
2802
def set_widths(self, ids, values):
2803
self.widths[ids] = values
2804
2805
def _update_vertexvbo(self):
2806
# print '_update_vertexvbo',self.format_ident()
2807
2808
vertices = self.get_vertices_array()
2809
x1 = vertices[:, 0, 0]
2810
y1 = vertices[:, 0, 1]
2811
z1 = vertices[:, 0, 2]
2812
2813
x2 = vertices[:, 1, 0]
2814
y2 = vertices[:, 1, 1]
2815
z2 = vertices[:, 1, 2]
2816
dx = x2-x1
2817
dy = y2-y1
2818
alpha_xy = np.arctan2(dy, dx)
2819
length_xy = np.sqrt(dx*dx + dy*dy)
2820
halfwidth = 0.5*self.get_widths_array()
2821
x1_new = x1.copy()
2822
y1_new = y1.copy()
2823
x2_new = x2.copy()
2824
y2_new = y2.copy()
2825
# print ' origvert'
2826
# print ' x1_new=',x1_new,x1_new.dtype
2827
# print ' x2_new=',x2_new,x2_new.dtype
2828
if self._is_fill.value:
2829
for style, id_style in LINEHEADS.iteritems():
2830
2831
# begin
2832
inds_style = np.flatnonzero(self.beginstyles.value == id_style)
2833
2834
if len(inds_style) > 0:
2835
2836
# print ' style',style,len(inds_style)
2837
# print ' x1_new=',x1_new,x1_new.dtype
2838
# print ' x2_new=',x2_new,x2_new.dtype
2839
self._update_vertexvbo_begin_fill(style, inds_style, x1_new, y1_new,
2840
z1, x2, y2, z2, length_xy, alpha_xy, halfwidth)
2841
2842
# end
2843
inds_style = np.flatnonzero(self.endstyles.value == id_style)
2844
if len(inds_style) > 0:
2845
self._update_vertexvbo_end_fill(style, inds_style, x1, y1, z1, x2_new,
2846
y2_new, z2, length_xy, alpha_xy, halfwidth)
2847
2848
self._update_vertexvbo_line_fill(x1_new, y1_new, z1, x2_new, y2_new, z2,
2849
length_xy, alpha_xy, halfwidth, len(self))
2850
2851
def _update_vertexvbo_line_fill(self, x1, y1, z1, x2, y2, z2, length_xy, alpha_xy, halfwidth, n):
2852
# print '_update_vertexvbo_line_fill'
2853
# this allows different color indexing for polyline
2854
# TODO n
2855
# if inds_colors is None:
2856
#n = len(self)
2857
# else:
2858
# n = None
2859
2860
#n_vert = self.get_n_vert()
2861
#dphi = np.pi/(n_vert-1)
2862
2863
#beta = alpha_xy+np.pi/2
2864
# print ' alpha_xy\n',alpha_xy/np.pi*180
2865
# print ' halfwidth\n',halfwidth
2866
# print ' x1\n',x1
2867
# print ' length_xy=',length_xy
2868
# print ' length_xy-self.widths.value=',(length_xy-self.widths.value)
2869
2870
# self.is_righthalf.value
2871
xr1 = x1 + self.is_lefthalf.value * halfwidth * np.cos(alpha_xy+np.pi/2)
2872
yr1 = y1 + self.is_lefthalf.value * halfwidth * np.sin(alpha_xy+np.pi/2)
2873
2874
xr2 = x2 + self.is_lefthalf.value * halfwidth * np.cos(alpha_xy+np.pi/2)
2875
yr2 = y2 + self.is_lefthalf.value * halfwidth * np.sin(alpha_xy+np.pi/2)
2876
2877
xr3 = x2 + self.is_righthalf.value * halfwidth * np.cos(alpha_xy-np.pi/2)
2878
yr3 = y2 + self.is_righthalf.value * halfwidth * np.sin(alpha_xy-np.pi/2)
2879
2880
xr4 = x1 + self.is_righthalf.value * halfwidth * np.cos(alpha_xy-np.pi/2)
2881
yr4 = y1 + self.is_righthalf.value * halfwidth * np.sin(alpha_xy-np.pi/2)
2882
2883
# print '_update_vertexvbo ',n,n_vert,self._is_fill.value
2884
# print ' x\n',x
2885
# print ' y\n',y
2886
# print ' z\n',z
2887
n_vpe = 4
2888
vertices = np.zeros((len(xr1), n_vpe * 3), dtype=np.float32)
2889
2890
vertices[:, 0] = xr1
2891
vertices[:, 1] = yr1
2892
vertices[:, 2] = z1
2893
2894
vertices[:, 3] = xr2
2895
vertices[:, 4] = yr2
2896
vertices[:, 5] = z2
2897
2898
vertices[:, 6] = xr3
2899
vertices[:, 7] = yr3
2900
vertices[:, 8] = z2
2901
2902
vertices[:, 9] = xr4
2903
vertices[:, 10] = yr4
2904
vertices[:, 11] = z1
2905
2906
# print ' vertices=\n',vertices
2907
self.get_vbo('line_fill').update_vertices(vertices, n)
2908
2909
#self._vertexvbo_fill = vbo.VBO(vertices.reshape((-1,3)))
2910
#self._indexvbo_fill = vbo.VBO(np.arange(self._n_vert*self._n_elem_fill, dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
2911
2912
def _update_vertexvbo_begin_fill(self, style, inds_style, x1_new, y1_new, z1, x2, y2, z2, length_xy, alpha_xy, halfwidth):
2913
ident_vbo = ('begin', 'fill', style)
2914
headvbo = self.get_vbo(ident_vbo)
2915
# print '_update_vertexvbo_begin_fill'
2916
2917
n = len(inds_style)
2918
alphastretch = 1.0
2919
n_vert = 6
2920
if style == 'bevel':
2921
n_vert = 6
2922
arrowstretch = 1.0
2923
2924
if style == 'triangle':
2925
n_vert = 3
2926
arrowstretch = self.arrowstretch.value
2927
2928
if style == 'arrow':
2929
n_vert = 3
2930
alphastretch = 1.2
2931
arrowstretch = self.arrowstretch.value
2932
radius = arrowstretch*halfwidth[inds_style]
2933
if style != 'bevel':
2934
x1_new[inds_style] = x2[inds_style] - (length_xy[inds_style]-radius)*np.cos(alpha_xy[inds_style])
2935
y1_new[inds_style] = y2[inds_style] - (length_xy[inds_style]-radius)*np.sin(alpha_xy[inds_style])
2936
2937
# print ' x1_new=',x1_new,x1_new.dtype,halfwidth[inds_style]
2938
# print ' y1_new=',y1_new,y1_new.dtype
2939
2940
if self.is_righthalf.value:
2941
alpha_end = np.pi/2
2942
else:
2943
n_vert = int(0.5*n_vert+0.5)
2944
alpha_end = 0.0
2945
2946
if self.is_lefthalf.value:
2947
alpha_start = -np.pi/2
2948
else:
2949
n_vert = int(0.5*n_vert+0.5)
2950
alpha_start = 0.0
2951
2952
dphi = (alpha_end-alpha_start)/(n_vert-1)
2953
alphas = alpha_xy[inds_style]+(alphastretch*np.arange(alpha_start, alpha_end+dphi, dphi)+np.pi).reshape(-1, 1)
2954
2955
# print ' alpha_xy\n',alpha_xy/np.pi*180
2956
# print ' alphas=alpha0+phi\n',alphas/np.pi*180
2957
2958
x = np.cos(alphas) * radius + x1_new[inds_style]
2959
y = np.sin(alphas) * radius + y1_new[inds_style]
2960
2961
z = np.ones((n_vert, 1)) * z1[inds_style]
2962
2963
# print '_update_vertexvbo ',n,n_vert,self._is_fill.value
2964
# print ' x\n',x
2965
# print ' y\n',y
2966
# print ' z\n',z
2967
2968
# print '_update_vertexvbo_fill',n,len(x),n_vert,self._n_vpe_fill
2969
xf = x.transpose().flatten() # +0.5
2970
yf = y.transpose().flatten() # +0.5
2971
zf = z.transpose().flatten()
2972
xcf = (np.ones((n_vert, 1)) * x1_new[inds_style]).transpose().flatten()
2973
ycf = (np.ones((n_vert, 1)) * y1_new[inds_style]).transpose().flatten()
2974
# print ' xcf\n',xcf
2975
# print ' ycf\n',ycf
2976
2977
# create and compose main vertices array
2978
n_elem_fill = (n_vert-1)*n
2979
2980
n_vpe = headvbo.get_vpe()
2981
# print ' n_elem_fill ',self._n_elem_fill
2982
# print ' n_vpe',n_vpe
2983
vertices = np.zeros((n_elem_fill, n_vpe * 3), dtype=np.float32)
2984
# print ' vertices.reshape((-1,3)).shape',vertices.reshape((-1,3)).shape
2985
#zf = z.transpose().flatten()
2986
2987
ind = np.arange(0, n*n_vert).reshape(n, n_vert)[:, :-1].flatten()
2988
2989
vertices[:, 0] = xf[ind]
2990
vertices[:, 1] = yf[ind]
2991
vertices[:, 2] = zf[ind]
2992
2993
vertices[:, 3] = xcf[ind]
2994
vertices[:, 4] = ycf[ind]
2995
vertices[:, 5] = zf[ind]
2996
2997
ind2 = np.arange(0, n*n_vert).reshape(n, n_vert)[:, 1:].flatten()
2998
vertices[:, 6] = xf[ind2]
2999
vertices[:, 7] = yf[ind2]
3000
vertices[:, 8] = zf[ind2]
3001
# print ' vertices=\n',vertices
3002
headvbo.update_vertices(vertices, inds=inds_style)
3003
3004
#self._vertexvbo_fill = vbo.VBO(vertices.reshape((-1,3)))
3005
#self._indexvbo_fill = vbo.VBO(np.arange(self._n_vert*self._n_elem_fill, dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
3006
3007
def _update_vertexvbo_end_fill(self, style, inds_style, x1, y1, z1, x2_new, y2_new, z2, length_xy, alpha_xy, halfwidth):
3008
ident_vbo = ('end', 'fill', style)
3009
headvbo = self.get_vbo(ident_vbo)
3010
# print '_update_vertexvbo_end_fill',style
3011
3012
n = len(inds_style)
3013
alphastretch = 1.0
3014
n_vert = 6
3015
arrowstretch = 1.0
3016
if style == 'bevel':
3017
n_vert = 6
3018
3019
if style == 'triangle':
3020
n_vert = 3
3021
arrowstretch = self.arrowstretch.value
3022
3023
if style == 'arrow':
3024
n_vert = 3
3025
alphastretch = 1.2
3026
arrowstretch = self.arrowstretch.value
3027
radius = arrowstretch*halfwidth[inds_style]
3028
3029
if style != 'bevel':
3030
x2_new[inds_style] = x1[inds_style] + (length_xy[inds_style]-radius)*np.cos(alpha_xy[inds_style])
3031
y2_new[inds_style] = y1[inds_style] + (length_xy[inds_style]-radius)*np.sin(alpha_xy[inds_style])
3032
3033
if self.is_lefthalf.value:
3034
alpha_end = np.pi/2
3035
else:
3036
n_vert = int(0.5*n_vert+0.5)
3037
alpha_end = 0.0
3038
3039
if self.is_righthalf.value:
3040
alpha_start = -np.pi/2
3041
else:
3042
n_vert = int(0.5*n_vert+0.5)
3043
alpha_start = 0.0
3044
3045
dphi = (alpha_end-alpha_start)/(n_vert-1)
3046
alphas = alpha_xy[inds_style]+alphastretch*np.arange(alpha_start, alpha_end+dphi, dphi).reshape(-1, 1)
3047
3048
dphi = np.pi/(n_vert-1)
3049
3050
# print ' alpha_xy\n',alpha_xy/np.pi*180
3051
# print ' alphas=alpha0+phi\n',alphas/np.pi*180
3052
# print ' n_vert',n_vert,dphi/np.pi*180
3053
3054
# print ' length_xy=',length_xy
3055
# print ' length_xy-self.widths.value=',(length_xy-self.widths.value)
3056
# print ' x2=',x2,x2.dtype
3057
3058
# print ' y2_new=',y2_new,y2_new.dtype
3059
x = np.cos(alphas) * radius + x2_new[inds_style]
3060
y = np.sin(alphas) * radius + y2_new[inds_style]
3061
3062
z = np.ones((n_vert, 1)) * z2[inds_style]
3063
3064
# print '_update_vertexvbo ',n,n_vert,self._is_fill.value
3065
# print ' x\n',x
3066
# print ' y\n',y
3067
# print ' z\n',z
3068
3069
# print '_update_vertexvbo_fill',n,len(x),n_vert,self._n_vpe_fill
3070
xf = x.transpose().flatten() # +0.5
3071
yf = y.transpose().flatten() # +0.5
3072
zf = z.transpose().flatten()
3073
xcf = (np.ones((n_vert, 1)) * x2_new[inds_style]).transpose().flatten()
3074
ycf = (np.ones((n_vert, 1)) * y2_new[inds_style]).transpose().flatten()
3075
# print ' xcf\n',xcf
3076
# print ' ycf\n',ycf
3077
3078
# create and compose main vertices array
3079
n_elem_fill = (n_vert-1)*n
3080
3081
n_vpe = headvbo.get_vpe()
3082
# print ' n_elem_fill ',self._n_elem_fill
3083
# print ' n_vpe',n_vpe
3084
vertices = np.zeros((n_elem_fill, n_vpe * 3), dtype=np.float32)
3085
# print ' vertices.reshape((-1,3)).shape',vertices.reshape((-1,3)).shape
3086
#zf = z.transpose().flatten()
3087
3088
ind = np.arange(0, n*n_vert).reshape(n, n_vert)[:, :-1].flatten()
3089
3090
vertices[:, 0] = xf[ind]
3091
vertices[:, 1] = yf[ind]
3092
vertices[:, 2] = zf[ind]
3093
3094
vertices[:, 3] = xcf[ind]
3095
vertices[:, 4] = ycf[ind]
3096
vertices[:, 5] = zf[ind]
3097
3098
ind2 = np.arange(0, n*n_vert).reshape(n, n_vert)[:, 1:].flatten()
3099
vertices[:, 6] = xf[ind2]
3100
vertices[:, 7] = yf[ind2]
3101
vertices[:, 8] = zf[ind2]
3102
# print ' vertices=\n',vertices
3103
headvbo.update_vertices(vertices, inds=inds_style)
3104
3105
#self._vertexvbo_fill = vbo.VBO(vertices.reshape((-1,3)))
3106
#self._indexvbo_fill = vbo.VBO(np.arange(self._n_vert*self._n_elem_fill, dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
3107
3108
def pick(self, p, detectwidth=0.1):
3109
"""
3110
Returns a binary vector which is True values for lines that have been selected
3111
by point p.
3112
3113
"""
3114
# print 'pick'
3115
if len(self) == 0:
3116
return np.array([], np.int)
3117
3118
vertices = self.get_vertices_array()
3119
x1 = vertices[:, 0, 0]
3120
y1 = vertices[:, 0, 1]
3121
3122
x2 = vertices[:, 1, 0]
3123
y2 = vertices[:, 1, 1]
3124
3125
# print ' x1', x1
3126
# print ' x2', x2
3127
dw = 0.5*(self.get_widths_array()+detectwidth)
3128
return self._ids[get_dist_point_to_segs(p, x1, y1, x2, y2, is_ending=True) < dw*dw]
3129
3130
3131
class Polylines(Fancylines):
3132
def __init__(self, ident, parent, name='Polylines', joinstyle=FLATHEAD, **kwargs):
3133
Fancylines.__init__(self, ident, parent, name=name, **kwargs)
3134
3135
# ident of drawobject used for animations
3136
# must be defined AFTER init_common
3137
self._ident_drawobj_anim = 'anim_polylines'
3138
3139
# FLATHEAD = 0
3140
# BEVELHEAD = 1
3141
self.add(cm.AttrConf('joinstyle', joinstyle,
3142
groupnames=['options'],
3143
perm='rw',
3144
is_save=True,
3145
is_plugin=False,
3146
name='Joinstyle',
3147
info='Joinstyle of line segments.',
3148
))
3149
3150
self.delete('vertices')
3151
self.add_col(am.ListArrayConf('vertices',
3152
# None,
3153
# dtype=np.object,
3154
groupnames=['_private'],
3155
perm='rw',
3156
name='Vertex',
3157
unit='m',
3158
is_save=True,
3159
info='Vertex coordinate vectors of points. Example with 2 vertex: [[[x11,y11,z11],[x12,y12,z12]],[[x21,y21,z21],[x22,y22,z122]],...]',
3160
))
3161
3162
def begin_animation(self, id_target):
3163
3164
self._id_target = id_target
3165
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
3166
3167
self.id_anim = self._drawobj_anim.add_drawobj( # make a copy as array, otherwise instance is copied
3168
np.array(self.get_vertices(id_target), np.float32).tolist(),
3169
np.array(self.get_widths(id_target), np.float32),
3170
self.color_anim.get_value(),
3171
beginstyle=self.beginstyles[id_target],
3172
endstyle=self.endstyles[id_target],
3173
)
3174
# print 'begin_animation',self.ident,id_target,self._drawobj_anim
3175
# print ' vert=',self.vertices[id_target]
3176
return True
3177
3178
def append_vert_to_animation(self, vert):
3179
# print 'append_vert_to_animation',vert, type(vert)
3180
# for _id in self.get_ids():
3181
# print ' main.vertices',_id,self.vertices[_id], type(self.vertices[_id])
3182
# for _id in self._drawobj_anim.get_ids():
3183
# print ' anim.vertices',_id,self._drawobj_anim.vertices[_id], type(self._drawobj_anim.vertices[_id])
3184
self._drawobj_anim.get_vertices(self.id_anim).append(vert)
3185
#vertex = self._drawobj_anim.get_vertices(self.id_anim).tolist()
3186
# self._drawobj_anim.set_vertices.append(vert.tolist())
3187
# print ' vertices',self._drawobj_anim.vertices[self.id_anim],type(self._drawobj_anim.vertices[self.id_anim])
3188
#vertices = self._drawobj_anim.vertices[self.id_anim]
3189
# vertices.append(vert)
3190
# self._drawobj_anim.vertices[self.id_anim]= vertices#list(np.array(vertices,np.float32))
3191
3192
# print ' vertices',vertices,type(vertices)
3193
# print ' self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim],type(self._drawobj_anim.vertices[self.id_anim])
3194
self._drawobj_anim._update_vertexvbo()
3195
self._drawobj_anim._update_colorvbo()
3196
return len(self._drawobj_anim.get_vertices(self.id_anim))-1 # vertex ind of next
3197
3198
def end_animation(self, is_del_last_vert=False):
3199
# print 'end_animation',self.ident,self._id_target
3200
# print ' verices =',self._drawobj_anim.vertices[self.id_anim]
3201
if is_del_last_vert:
3202
# cut of last one because duplicated after adding
3203
self.set_vertices(self._id_target, self._drawobj_anim.get_vertices(self.id_anim)[:-1])
3204
else:
3205
self.set_vertices(self._id_target, self._drawobj_anim.get_vertices(self.id_anim))
3206
3207
self.del_animation()
3208
# self._drawobj_anim.del_drawobj(self.id_anim)
3209
self._update_vertexvbo()
3210
self._update_colorvbo()
3211
return True
3212
3213
def _make_lines(self):
3214
n_lines_tot = 0
3215
for polyline in self.get_vertices_array():
3216
n_seg = len(polyline)
3217
# if n_seg>1:
3218
n_lines_tot += n_seg-1
3219
3220
linevertices = np.zeros((n_lines_tot, 2, 3), np.float32)
3221
vertexinds = np.zeros((n_lines_tot, 2), np.int32)
3222
3223
polyinds = np.zeros(n_lines_tot, np.int32)
3224
linebeginstyles = np.zeros(n_lines_tot, np.int32)
3225
lineendstyles = np.zeros(n_lines_tot, np.int32)
3226
3227
beginstyles = self.beginstyles.value
3228
endstyles = self.endstyles.value
3229
joinstyle = self.joinstyle.value
3230
ind = 0
3231
ind_line = 0
3232
for polyline in self.get_vertices_array():
3233
# print ' =======',len(polyline)
3234
n_seg = len(polyline)
3235
# print ' polyline\n',polyline
3236
3237
if n_seg > 1:
3238
polyvinds = range(n_seg)
3239
# print ' polyvinds\n',polyvinds
3240
vi = np.zeros((2*n_seg-2), np.int32)
3241
vi[0] = polyvinds[0]
3242
vi[-1] = polyvinds[-1]
3243
3244
# Important type conversion!!
3245
v = np.zeros((2*n_seg-2, 3), np.float32)
3246
v[0] = polyline[0]
3247
v[-1] = polyline[-1]
3248
if len(v) > 2:
3249
v[1:-1] = np.repeat(polyline[1:-1], 2, 0)
3250
vi[1:-1] = np.repeat(polyvinds[1:-1], 2)
3251
3252
n_lines = len(v)/2
3253
# print ' v\n',v
3254
inds_polyline = range(ind_line, ind_line+n_lines)
3255
3256
polyinds[inds_polyline] = ind
3257
3258
linebeginstyles[inds_polyline] = joinstyle
3259
linebeginstyles[inds_polyline[0]] = beginstyles[ind]
3260
3261
lineendstyles[inds_polyline] = joinstyle
3262
lineendstyles[inds_polyline[-1]] = endstyles[ind]
3263
3264
linevertices[inds_polyline] = v.reshape((-1, 2, 3))
3265
vertexinds[inds_polyline] = vi.reshape((-1, 2))
3266
3267
ind_line += n_lines
3268
ind += 1
3269
else:
3270
# empty polygon treatment
3271
pass
3272
3273
# print ' linevertex\n',linevertices
3274
3275
self._linevertices = linevertices
3276
self._polyinds = polyinds
3277
self._vertexinds = vertexinds
3278
self._linebeginstyles = linebeginstyles
3279
self._lineendstyles = lineendstyles
3280
3281
def _update_vertexvbo(self):
3282
# print '_update_vertexvbo',self.ident
3283
self._make_lines()
3284
vertices = self._linevertices
3285
x1 = vertices[:, 0, 0]
3286
y1 = vertices[:, 0, 1]
3287
z1 = vertices[:, 0, 2]
3288
3289
x2 = vertices[:, 1, 0]
3290
y2 = vertices[:, 1, 1]
3291
z2 = vertices[:, 1, 2]
3292
dx = x2-x1
3293
dy = y2-y1
3294
alpha_xy = np.arctan2(dy, dx)
3295
length_xy = np.sqrt(dx*dx + dy*dy)
3296
halfwidth = 0.5*self.get_widths_array()[self._polyinds]
3297
# if self.ident =='lanedraws':
3298
# print '_update_vertexvbo',self.ident
3299
# print ' halfwidth',halfwidth
3300
# print ' x1',x1
3301
# print ' y1',y1
3302
3303
x1_new = x1.copy()
3304
y1_new = y1.copy()
3305
x2_new = x2.copy()
3306
y2_new = y2.copy()
3307
# print ' origvert'
3308
# print ' x1_new=',x1_new,x1_new.dtype
3309
# print ' x2_new=',x2_new,x2_new.dtype
3310
if self._is_fill.value:
3311
for style, id_style in LINEHEADS.iteritems():
3312
3313
# begin
3314
inds_style = np.flatnonzero(self._linebeginstyles == id_style)
3315
3316
if len(inds_style) > 0:
3317
3318
# print ' style',style,len(inds_style)
3319
# print ' x1_new=',x1_new,x1_new.dtype
3320
# print ' x2_new=',x2_new,x2_new.dtype
3321
self._update_vertexvbo_begin_fill(style, inds_style, x1_new, y1_new,
3322
z1, x2, y2, z2, length_xy, alpha_xy, halfwidth)
3323
3324
# end
3325
inds_style = np.flatnonzero(self._lineendstyles == id_style)
3326
if len(inds_style) > 0:
3327
self._update_vertexvbo_end_fill(style, inds_style, x1, y1, z1, x2_new,
3328
y2_new, z2, length_xy, alpha_xy, halfwidth)
3329
3330
self._update_vertexvbo_line_fill(x1_new, y1_new, z1, x2_new, y2_new, z2,
3331
length_xy, alpha_xy, halfwidth, len(vertices))
3332
3333
def _update_colorvbo(self):
3334
n = len(self._polyinds)
3335
#n_vert = self.get_n_vert()
3336
# print '_update_colorvbo fancyline'
3337
#self._linecolors = np.array(linecolors, np.float32)
3338
#self._linecolors_highl = np.array(linecolors_highl, np.float32)
3339
if self._is_outline.value:
3340
colors = self.colors.value[self._polyinds] + \
3341
self.are_highlighted.value[self._polyinds].reshape(n, 1)*self.colors_highl.value[self._polyinds]
3342
for _vbo in self.get_vbos():
3343
if not _vbo.is_fill():
3344
_vbo.update_colors(colors)
3345
3346
if self._is_fill.value:
3347
colors = self.colors_fill.value[self._polyinds] + self.are_highlighted.value[self._polyinds].reshape(
3348
n, 1)*self.colors_fill_highl.value[self._polyinds]
3349
for _vbo in self.get_vbos():
3350
if _vbo.is_fill():
3351
_vbo.update_colors(colors)
3352
3353
def pick(self, p, detectwidth=0.1):
3354
"""
3355
Returns a binary vector which is True values for lines that have been selected
3356
by point p.
3357
3358
In particular, an element of this vector is True if the minimum distance
3359
between the respective line to point p is less than detectwidth
3360
"""
3361
# print 'pick'
3362
if len(self) == 0:
3363
return np.array([], np.int)
3364
3365
vertices = self._linevertices
3366
x1 = vertices[:, 0, 0]
3367
y1 = vertices[:, 0, 1]
3368
3369
x2 = vertices[:, 1, 0]
3370
y2 = vertices[:, 1, 1]
3371
3372
# print ' x1', x1
3373
# print ' x2', x2
3374
halfwidths = 0.5*(self.get_widths_array()[self._polyinds]+detectwidth)
3375
return self._ids[self._polyinds[get_dist_point_to_segs(p, x1, y1, x2, y2, is_ending=True) < halfwidths*halfwidths]]
3376
3377
def pick_handle(self, coord, detectwidth=0.1):
3378
"""
3379
Retuns list [ id, ind_vert] when handle is near coord,
3380
otherwise []
3381
3382
"""
3383
# print 'pick_handle',self.get_ident(),len(self)
3384
dw = detectwidth**2
3385
3386
if len(self) == 0:
3387
return np.zeros((0, 2), np.int)
3388
3389
# if self.ident not in [ 'lines','fancylines','polylines']:
3390
# return np.zeros((0,2),np.int)
3391
3392
vertices = self._linevertices # self.get_vertices_array()
3393
handles = []
3394
# print ' vertices',vertices
3395
# print ' vertices.shape',vertices.shape
3396
dx = vertices[:, 0, 0]-coord[0]
3397
dy = vertices[:, 0, 1]-coord[1]
3398
inds = np.flatnonzero(dx*dx+dy*dy < dw)
3399
3400
ids = self._ids[self._polyinds[inds]]
3401
handle1 = np.ones((len(ids), 2), np.int)
3402
handle1[:, 0] = ids
3403
handle1[:, 1] = self._vertexinds[inds, 0]
3404
# print ' ',d,handle1
3405
3406
dx = vertices[:, 1, 0]-coord[0]
3407
dy = vertices[:, 1, 1]-coord[1]
3408
inds = np.flatnonzero(dx*dx+dy*dy < dw)
3409
ids = self._ids[self._polyinds[inds]]
3410
handle2 = np.ones((len(ids), 2), np.int)
3411
handle2[:, 0] = ids
3412
handle2[:, 1] = self._vertexinds[inds, 1]
3413
# print ' ',d,handle2
3414
handles = np.concatenate((handle1, handle2), 0)
3415
3416
return handles
3417
3418
def get_boundingbox(self):
3419
if len(self) == 0:
3420
return None
3421
vv = self._linevertices
3422
# TODOD: can be done faster
3423
return np.array([[np.min(vv[:, :, 0]), np.min(vv[:, :, 1]), np.min(vv[:, :, 2])],
3424
[np.max(vv[:, :, 0]), np.max(vv[:, :, 1]), np.max(vv[:, :, 2])]
3425
], float)
3426
3427
3428
class Circles(DrawobjMixin):
3429
3430
def __init__(self, ident, parent, name='Circles',
3431
is_parentobj=False,
3432
is_fill=True, # Fill objects,
3433
is_outline=True, # show outlines
3434
c_highl=0.3,
3435
n_vert=7, # default number of vertex per circle
3436
linewidth=2,
3437
**kwargs):
3438
3439
self.init_common(ident, parent=parent, name=name,
3440
linewidth=linewidth,
3441
is_parentobj=is_parentobj,
3442
n_vert=n_vert,
3443
is_fill=is_fill,
3444
is_outline=is_outline,
3445
c_highl=c_highl,
3446
**kwargs)
3447
# ident of drawobject used for animations
3448
# must be defined AFTER init_common
3449
self._ident_drawobj_anim = 'anim_circles'
3450
3451
if is_outline:
3452
self.add_vbo(Vbo('outline', GL_LINES, 2, objtype='outline'))
3453
if is_fill:
3454
self.add_vbo(Vbo('fill', GL_TRIANGLES, 3, objtype='fill'))
3455
3456
self.add_col(am.ArrayConf('centers', np.zeros(3, dtype=np.float32),
3457
dtype=np.float32,
3458
groupnames=['_private'],
3459
perm='rw',
3460
name='Center',
3461
unit='m',
3462
is_save=True,
3463
info='Center coordinate. Example: [x,y,z]',
3464
))
3465
3466
self.add_col(am.ArrayConf('radii', 1.0,
3467
dtype=np.float32,
3468
groupnames=['_private'],
3469
perm='rw',
3470
name='Radius',
3471
is_save=True,
3472
info='Circle radius',
3473
))
3474
3475
def is_tool_allowed(self, tool, id_drawobj=-1):
3476
"""
3477
Returns True if this tool can be applied to this drawobj.
3478
Optionally a particular drawobj can be specified with id_drawobj.
3479
"""
3480
# basic tools:
3481
# return tool.ident not in ['configure','select_handles','delete','move','stretch']
3482
return True
3483
3484
def get_centers_array(self):
3485
return self.centers.value
3486
3487
def get_radii_array(self):
3488
return self.radii.value
3489
3490
def get_boundingbox(self):
3491
if len(self) == 0:
3492
return None
3493
vv = self.get_centers_array()
3494
rad = self.get_radii_array()
3495
# TODOD: can be done faster
3496
return np.array([[np.min(vv[:, 0]-rad), np.min(vv[:, 1]-rad), np.min(vv[:, 2])],
3497
[np.max(vv[:, 0]+rad), np.max(vv[:, 1]+rad), np.max(vv[:, 2])]
3498
], float)
3499
3500
def add_drawobj(self, center, radius,
3501
color, color_fill=None,
3502
color_highl=None, color_fill_highl=None,
3503
is_update=True):
3504
3505
if color_fill is None:
3506
color_fill = color
3507
3508
if color_highl is None:
3509
color_highl = self._get_colors_highl(np.array([color]))[0]
3510
3511
if color_fill_highl is None:
3512
color_fill_highl = self._get_colors_highl(np.array([color_fill]))[0]
3513
3514
_id = self.add_row(centers=center,
3515
radii=radius,
3516
colors=color,
3517
colors_highl=color_highl,
3518
colors_fill=color_fill,
3519
colors_fill_highl=color_fill_highl,
3520
)
3521
if is_update:
3522
self._update_vertexvbo()
3523
self._update_colorvbo()
3524
return _id
3525
3526
def add_drawobjs(self, centers, radii,
3527
colors, colors_fill=None,
3528
colors_highl=None, colors_fill_highl=None,
3529
is_update=True):
3530
# print 'Circles.add_drawobjs',self._is_fill.value,self._is_outline.value
3531
if colors_fill is None:
3532
colors_fill = colors
3533
3534
if colors_highl is None:
3535
colors_highl = self._get_colors_highl(colors)
3536
3537
if colors_fill_highl is None:
3538
colors_fill_highl = self._get_colors_highl(colors_fill)
3539
3540
# print ' colors',colors[:2]
3541
# print ' colors_highl',colors_highl[:2]
3542
3543
ids = self.add_rows(len(centers),
3544
centers=centers,
3545
radii=radii,
3546
colors=colors,
3547
colors_highl=colors_highl,
3548
colors_fill=colors_fill,
3549
colors_fill_highl=colors_fill_highl,
3550
)
3551
if is_update:
3552
self._update_vertexvbo()
3553
self._update_colorvbo()
3554
return ids
3555
3556
def begin_animation(self, id_target):
3557
3558
self._id_target = id_target
3559
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
3560
self.id_anim = self._drawobj_anim.add_drawobj(np.array(self.centers[id_target]),
3561
1.0*self.radii[id_target],
3562
self.color_anim.value,
3563
)
3564
# print 'begin_animation',self.ident,_id,self._drawobj_anim
3565
return True
3566
3567
def set_anim(self, _id, drawobjelem_anim):
3568
# print 'set_anim',self.ident,_id,drawobj_anim
3569
(drawobj_anim, id_anim) = drawobjelem_anim
3570
# print ' self.vertices[_id]=',self.vertices[_id]
3571
# print ' drawobjset_anim.vertices[id_anim]=',drawobjset_anim.vertices[id_anim]
3572
self.centers[_id] = np.array(drawobj_anim.centers[id_anim])
3573
self.radii[_id] = 1.0*drawobj_anim.radii[id_anim]
3574
drawobj_anim.del_drawobj(id_anim)
3575
self._update_vertexvbo()
3576
return True
3577
3578
def end_animation(self, is_del_last_vert=False):
3579
# print 'end_animation',self.ident,_id,self._drawobj_anim
3580
self.centers[self._id_target] = np.array(self._drawobj_anim.centers[self.id_anim])
3581
self.radii[self._id_target] = 1.0*self._drawobj_anim.radii[self.id_anim]
3582
3583
self._drawobj_anim.del_drawobj(self.id_anim)
3584
self._update_vertexvbo()
3585
return True
3586
3587
def move(self, _id, vertex, vertex_delta):
3588
# print 'move',self.ident,_id, vertex_delta
3589
self.centers[_id] += vertex_delta
3590
# print ' vertices[id_anim]=',self.vertices[_id]
3591
self._update_vertexvbo()
3592
return True
3593
3594
def stretch(self, _id, vertex, vertex_delta, ind_vertex):
3595
# print 'move',self.ident,_id, v
3596
#self.vertices[_id, ind_vertex] += vertex_delta
3597
3598
self.radii[_id] = np.sqrt(np.sum((vertex - self.centers[_id])**2))
3599
# print ' vertices[id_anim]=',self.vertices[_id]
3600
self._update_vertexvbo()
3601
return True
3602
3603
def _update_vertexvbo(self):
3604
3605
n = len(self)
3606
n_vert = self.get_n_vert()
3607
3608
# print '_update_vertexvbo ',n,n_vert,self._is_fill.value
3609
3610
# compute x,y,z of vertices of n objects
3611
dphi = 2*np.pi/(n_vert-1)
3612
phi = np.arange(0, 2*np.pi+dphi, dphi).reshape(-1, 1)
3613
3614
centers = self.get_centers_array()
3615
radii = self.get_radii_array()
3616
x = np.cos(phi)*radii+centers[:, 0]
3617
3618
y = np.sin(phi)*radii+centers[:, 1]
3619
3620
z = np.ones((n_vert, 1)) * centers[:, 2]
3621
# print ' x.shape=', x.shape
3622
if self._is_outline.value:
3623
self._update_vertexvbo_lines(x, y, z)
3624
3625
if self._is_fill.value:
3626
self._update_vertexvbo_fill(x, y, z)
3627
3628
def _update_vertexvbo_fill(self, x, y, z):
3629
n = len(self)
3630
n_vert = self.get_n_vert()
3631
# print '_update_vertexvbo_fill',n,len(x),n_vert#,self._n_vpe_fill
3632
xf = x.transpose().flatten() # +0.5
3633
yf = y.transpose().flatten() # +0.5
3634
zf = z.transpose().flatten()
3635
3636
centers = self.get_centers_array()
3637
#radii = self.get_radii_array()
3638
3639
xcf = (np.ones((n_vert, 1)) * centers[:, 0]).transpose().flatten()
3640
ycf = (np.ones((n_vert, 1)) * centers[:, 1]).transpose().flatten()
3641
3642
# create and compose main vertices array
3643
n_elem_fill = (n_vert-1)*n
3644
3645
#glDrawElements(GL_TRIANGLES, self._n_vert*self._n_elem_fill, GL_UNSIGNED_INT, None)
3646
# self._n_vert*self._n_elem_fill = n_vert * (n_vert-1)*n
3647
# repeat for each of the n objects: self._n_vpe_fill*(n_vert-1)
3648
# self._n_vpe * self._n_elem_fill = self._n_vpe * (n_vert-1)*n
3649
3650
n_vpe_fill = self.get_vbo('fill').get_vpe()
3651
# print ' n_elem_fill',n_elem_fill,n_vpe_fill
3652
vertices = np.zeros((n_elem_fill, n_vpe_fill * 3), dtype=np.float32)
3653
# print ' vertices.reshape((-1,3)).shape',vertices.reshape((-1,3)).shape
3654
zf = z.transpose().flatten()
3655
3656
ind = np.arange(0, n*n_vert).reshape(n, n_vert)[:, :-1].flatten()
3657
3658
vertices[:, 0] = xf[ind]
3659
vertices[:, 1] = yf[ind]
3660
vertices[:, 2] = zf[ind]
3661
3662
vertices[:, 3] = xcf[ind]
3663
vertices[:, 4] = ycf[ind]
3664
vertices[:, 5] = zf[ind]
3665
3666
ind2 = np.arange(0, n*n_vert).reshape(n, n_vert)[:, 1:].flatten()
3667
vertices[:, 6] = xf[ind2]
3668
vertices[:, 7] = yf[ind2]
3669
vertices[:, 8] = zf[ind2]
3670
3671
self.get_vbo('fill').update_vertices(vertices, n)
3672
#self._vertexvbo_fill = vbo.VBO(vertices.reshape((-1,3)))
3673
#self._indexvbo_fill = vbo.VBO(np.arange(self._n_vert*self._n_elem_fill, dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
3674
3675
def _update_vertexvbo_lines(self, x, y, z):
3676
# print '_update_vertexvbo_lines',len(x)
3677
n = len(self)
3678
n_vert = self.get_n_vert()
3679
3680
# create and compose main vertices array
3681
n_elem = (n_vert-1)*n
3682
3683
n_vpe = 2 # vertices per OGL element
3684
3685
vertices = np.zeros((n_elem, n_vpe * 3), dtype=np.float32)
3686
3687
# print ' vertices.reshape((-1,3)).shape',vertices.reshape((-1,3)).shape
3688
3689
xf = x.transpose().flatten()
3690
yf = y.transpose().flatten()
3691
zf = z.transpose().flatten()
3692
3693
ind = np.arange(0, n*n_vert).reshape(n, n_vert)[:, :-1].flatten()
3694
3695
vertices[:, 0] = xf[ind]
3696
vertices[:, 1] = yf[ind]
3697
vertices[:, 2] = zf[ind]
3698
3699
ind2 = np.arange(0, n*n_vert).reshape(n, n_vert)[:, 1:].flatten()
3700
vertices[:, 3] = xf[ind2]
3701
vertices[:, 4] = yf[ind2]
3702
vertices[:, 5] = zf[ind2]
3703
3704
self.get_vbo('outline').update_vertices(vertices, n)
3705
3706
def pick(self, p, detectwidth=0.1):
3707
"""
3708
Returns a binary vector which is True values for circles that have been selected
3709
by point p.
3710
3711
In particular, an element is selected if point p is within the circle
3712
"""
3713
if len(self) == 0:
3714
return np.array([], np.int)
3715
3716
#centers = self.centers.value
3717
centers = self.get_centers_array()
3718
radii = self.get_radii_array()+0.5*detectwidth
3719
dx = centers[:, 0]-p[0]
3720
dy = centers[:, 1]-p[1]
3721
return self._ids[dx*dx+dy*dy < (radii*radii)]
3722
3723
def pick_handle(self, coord, detectwidth=0.1):
3724
"""
3725
Retuns list [ id, ind_vert] when handle is near coord,
3726
otherwise []
3727
3728
"""
3729
if len(self) == 0:
3730
return np.zeros((0, 2), np.int)
3731
# print 'pick_handle',self.get_ident(),len(self)
3732
dw = detectwidth**2
3733
3734
centers = self.get_centers_array()
3735
radii = self.get_radii_array()
3736
dx = centers[:, 0]-coord[0]
3737
dy = centers[:, 1]-coord[1]
3738
r = dx*dx+dy*dy
3739
ids = self._ids[(r > radii*radii-dw) & (r < radii*radii+dw)]
3740
#handles = np.concatenate(( ids.reshape((len(ids),1)), np.zeros((len(ids),1),np.int)),1)
3741
3742
# print ' ids',ids
3743
# print ' handles',handles
3744
return np.concatenate((ids.reshape((len(ids), 1)), np.zeros((len(ids), 1), np.int)), 1)
3745
3746
3747
class Polygons(DrawobjMixin):
3748
def __init__(self, ident, parent, name='Polygons', **kwargs):
3749
self.init_common(ident, parent=parent, name=name,
3750
is_fill=False,
3751
is_outline=True,
3752
**kwargs)
3753
# ident of drawobject used for animations
3754
# must be defined AFTER init_common
3755
self._ident_drawobj_anim = 'anim_polygons'
3756
3757
if self._is_outline:
3758
self.add_vbo(Vbo('outline', GL_LINES, 2, objtype='outline'))
3759
if self._is_fill:
3760
self.add_vbo(Vbo('fill', GL_TRIANGLES, 3, objtype='fill'))
3761
3762
self.delete('vertices')
3763
self.add_col(am.ListArrayConf('vertices',
3764
# None,
3765
# dtype=np.object,
3766
groupnames=['_private'],
3767
perm='rw',
3768
name='Vertex',
3769
unit='m',
3770
is_save=True,
3771
info='3D coordinate list of Polygon Points.',
3772
))
3773
3774
def add_drawobj(self, vertex,
3775
color, color_fill=None,
3776
color_highl=None, color_fill_highl=None,
3777
is_update=True):
3778
3779
if color_fill is None:
3780
color_fill = color
3781
3782
if color_highl is None:
3783
color_highl = self._get_colors_highl(np.array([color]))[0]
3784
3785
if color_fill_highl is None:
3786
color_fill_highl = self._get_colors_highl(np.array([color_fill]))[0]
3787
3788
_id = self.add_row(vertices=vertex,
3789
colors=color,
3790
colors_highl=color_highl,
3791
colors_fill=color_fill,
3792
colors_fill_highl=color_fill_highl,
3793
)
3794
if is_update:
3795
self._update_vertexvbo()
3796
self._update_colorvbo()
3797
return _id
3798
3799
def add_drawobjs(self, vertices,
3800
colors, colors_fill=None,
3801
colors_highl=None, colors_fill_highl=None,
3802
is_update=True):
3803
3804
if colors_fill is None:
3805
colors_fill = colors
3806
3807
if colors_highl is None:
3808
colors_highl = self._get_colors_highl(colors)
3809
3810
if colors_fill_highl is None:
3811
colors_fill_highl = self._get_colors_highl(colors_fill)
3812
3813
ids = self.add_rows(len(vertices),
3814
vertices=vertices,
3815
colors=colors,
3816
colors_highl=colors_highl,
3817
colors_fill=colors_fill,
3818
colors_fill_highl=colors_fill_highl,
3819
)
3820
if is_update:
3821
self._update_vertexvbo()
3822
self._update_colorvbo()
3823
return ids
3824
3825
def begin_animation(self, id_target):
3826
3827
self._id_target = id_target
3828
self._drawobj_anim = self.parent.get_drawobj_by_ident(self._ident_drawobj_anim)
3829
self.id_anim = self._drawobj_anim.add_drawobj( # make a copy as array, otherwise instance is copied
3830
np.array(self.get_vertices(id_target), np.float32).tolist(),
3831
self.color_anim.get_value(),
3832
)
3833
# print 'begin_animation',self.ident,_id,self._drawobj_anim
3834
return True
3835
3836
def append_vert_to_animation(self, vert):
3837
# print 'append_vert_to_animation',vert, type(vert)
3838
# for _id in self.get_ids():
3839
# print ' main.vertices',_id,self.vertices[_id], type(self.vertices[_id])
3840
# for _id in self._drawobj_anim.get_ids():
3841
# print ' anim.vertices',_id,self._drawobj_anim.vertices[_id], type(self._drawobj_anim.vertices[_id])
3842
3843
self._drawobj_anim.get_vertices(self.id_anim).append(vert)
3844
# print ' vertices',self._drawobj_anim.vertices[self.id_anim],type(self._drawobj_anim.vertices[self.id_anim])
3845
#vertices = self._drawobj_anim.vertices[self.id_anim]
3846
# vertices.append(vert)
3847
# self._drawobj_anim.vertices[self.id_anim]= vertices#list(np.array(vertices,np.float32))
3848
3849
# print ' vertices',vertices,type(vertices)
3850
# print ' self._drawobj_anim.vertices[self.id_anim]',self._drawobj_anim.vertices[self.id_anim],type(self._drawobj_anim.vertices[self.id_anim])
3851
self._drawobj_anim._update_vertexvbo()
3852
self._drawobj_anim._update_colorvbo()
3853
return len(self._drawobj_anim.get_vertices(self.id_anim))-1 # vertex ind of next
3854
3855
# def get_vertices_array(self):
3856
# return self.vertices.value
3857
3858
def _make_lines(self):
3859
n_lines_tot = 0
3860
for polyline in self.get_vertices_array():
3861
n_lines_tot += len(polyline)
3862
3863
linevertices = np.zeros((n_lines_tot, 2, 3), np.float32)
3864
vertexinds = np.zeros((n_lines_tot, 2), np.int32)
3865
3866
polyinds = np.zeros(n_lines_tot, np.int32)
3867
linebeginstyles = np.zeros(n_lines_tot, np.int32)
3868
lineendstyles = np.zeros(n_lines_tot, np.int32)
3869
3870
ind = 0
3871
ind_line = 0
3872
3873
for polyline in self.get_vertices_array(): # self.vertices.value:
3874
# print ' ======='
3875
3876
# print ' polyline\n',polyline
3877
polyvinds = range(len(polyline))
3878
# print ' polyvinds\n',polyvinds
3879
vi = np.zeros((2*len(polyline)), np.int32)
3880
vi[0] = polyvinds[0]
3881
vi[-2] = polyvinds[-2]
3882
vi[-1] = polyvinds[-1]
3883
# print ' vi\n',vi
3884
3885
# Important type conversion!!
3886
v = np.zeros((2*len(polyline), 3), np.float32)
3887
v[0] = polyline[0]
3888
v[-2] = polyline[-1]
3889
v[-1] = polyline[0]
3890
# print ' v\n',v
3891
if len(v) > 3:
3892
v[1:-1] = np.repeat(polyline[1:], 2, 0)
3893
vi[1:-1] = np.repeat(polyvinds[1:], 2)
3894
n_lines = len(v)/2
3895
# print ' v\n',v
3896
inds_polyline = range(ind_line, ind_line+n_lines)
3897
3898
polyinds[inds_polyline] = ind
3899
linevertices[inds_polyline] = v.reshape((-1, 2, 3))
3900
vertexinds[inds_polyline] = vi.reshape((-1, 2))
3901
ind_line += n_lines
3902
ind += 1
3903
3904
self._linevertices = linevertices
3905
self._vertexinds = vertexinds
3906
self._polyinds = polyinds
3907
3908
def _update_vertexvbo(self):
3909
# print '_update_vertexvbo',self.format_ident()
3910
self._make_lines()
3911
3912
if self._is_outline.value:
3913
# print ' linevertices.reshape((-1,6))',self._linevertices.reshape((-1,6)),len(self._linevertices)
3914
self.get_vbo('outline').update_vertices(self._linevertices.reshape((-1, 6)), len(self._linevertices))
3915
#self._update_vertexvbo_line_fill(x1_new,y1_new,z1,x2_new,y2_new,z2,length_xy, alpha_xy,halfwidth,len(vertices))
3916
3917
# if self._is_fill.value:
3918
# self._update_vertexvbo_line_fill(x1_new,y1_new,z1,x2_new,y2_new,z2,length_xy, alpha_xy,halfwidth,len(vertices))
3919
3920
def _update_colorvbo(self):
3921
n = len(self._polyinds)
3922
#n_vert = self.get_n_vert()
3923
# print 'Polygons._update_colorvbo',self.ident,n
3924
# print ' colors',self.colors.value
3925
# print ' are_highlighted',self.are_highlighted.value
3926
#self._linecolors = np.array(linecolors, np.float32)
3927
#self._linecolors_highl = np.array(linecolors_highl, np.float32)
3928
if (self._is_outline.value) & (n > 0):
3929
colors = self.colors.value[self._polyinds] + \
3930
self.are_highlighted.value[self._polyinds].reshape(n, 1)*self.colors_highl.value[self._polyinds]
3931
self.get_vbo('outline').update_colors(colors)
3932
3933
# if self._is_fill.value:
3934
# colors = self.colors_fill.value[self._polyinds] + self.are_highlighted.value[self._polyinds].reshape(n,1)*self.colors_fill_highl.value[self._polyinds]
3935
# self.get_vbo('fill').update_colors(colors)
3936
3937
def pick(self, p, detectwidth=0.1):
3938
"""
3939
Returns a binary vector which is True values for lines that have been selected
3940
by point p.
3941
3942
In particular, an element of this vector is True if the minimum distance
3943
between the respective line to point p is less than detectwidth
3944
"""
3945
if len(self) == 0:
3946
return np.array([], np.int)
3947
3948
vertices = self._linevertices
3949
x1 = vertices[:, 0, 0]
3950
y1 = vertices[:, 0, 1]
3951
3952
x2 = vertices[:, 1, 0]
3953
y2 = vertices[:, 1, 1]
3954
3955
return self._ids[self._polyinds[get_dist_point_to_segs(p, x1, y1, x2, y2, is_ending=True) < detectwidth*detectwidth]]
3956
3957
def pick_handle(self, coord, detectwidth=0.1):
3958
"""
3959
Retuns list [ id, ind_vert] when handle is near coord,
3960
otherwise []
3961
3962
"""
3963
# print 'pick_handle',self.get_ident(),len(self),detectwidth
3964
dw = detectwidth ** 2 # np.sqrt(detectwidth)
3965
3966
if len(self) == 0:
3967
return np.zeros((0, 2), np.int)
3968
3969
# if self.ident not in [ 'lines','fancylines','polylines']:
3970
# return np.zeros((0,2),np.int)
3971
3972
vertices = self._linevertices # self.get_vertices_array()
3973
handles = []
3974
# print ' vertices',vertices
3975
# print ' vertices.shape',vertices.shape
3976
dx = vertices[:, 0, 0]-coord[0]
3977
dy = vertices[:, 0, 1]-coord[1]
3978
inds = np.flatnonzero(dx*dx+dy*dy < dw)
3979
3980
ids = self._ids[self._polyinds[inds]]
3981
handle1 = np.ones((len(ids), 2), np.int)
3982
handle1[:, 0] = ids
3983
handle1[:, 1] = self._vertexinds[inds, 0]
3984
# print ' ',d,handle1
3985
3986
dx = vertices[:, 1, 0]-coord[0]
3987
dy = vertices[:, 1, 1]-coord[1]
3988
inds = np.flatnonzero(dx*dx+dy*dy < dw)
3989
ids = self._ids[self._polyinds[inds]]
3990
handle2 = np.ones((len(ids), 2), np.int)
3991
handle2[:, 0] = ids
3992
handle2[:, 1] = self._vertexinds[inds, 1]
3993
# print ' ',d,handle2
3994
handles = np.concatenate((handle1, handle2), 0)
3995
3996
# print ' found',len(np.flatnonzero(handles))
3997
return handles
3998
3999
def get_boundingbox(self):
4000
if len(self) == 0:
4001
return None
4002
vv = self._linevertices
4003
# TODOD: can be done faster
4004
return np.array([[np.min(vv[:, :, 0]), np.min(vv[:, :, 1]), np.min(vv[:, :, 2])],
4005
[np.max(vv[:, :, 0]), np.max(vv[:, :, 1]), np.max(vv[:, :, 2])]
4006
], float)
4007
4008
4009
class OGLdrawing(am.ArrayObjman):
4010
"""
4011
Class holding an ordered list of all OGL draw objects.
4012
This class manages also the order in which the draw objects are rendered.
4013
4014
The basic idea is that an instance of this class can be passed to
4015
different OGL rendering canvas.
4016
"""
4017
4018
def __init__(self, ident='drawing', parent=None, name='OGL drawing', info='List of OGL draw objects'):
4019
"""
4020
Holds all drawing objects and provides basic access.
4021
"""
4022
self._init_objman(ident, parent=parent, name=name, info=info)
4023
self.add_col(cm.ObjsConf('drawobjects',
4024
groupnames=['options'],
4025
name='Draw object',
4026
info='Object, containing data and rendering methods.',
4027
))
4028
4029
self.add_col(am.ArrayConf('idents', '',
4030
dtype='object',
4031
perm='r',
4032
is_index=True,
4033
name='ID',
4034
info='Ident string of draw object.',
4035
))
4036
4037
self.add_col(am.ArrayConf('layers', -1.0,
4038
groupnames=['options'],
4039
perm='rw',
4040
#is_index = True,
4041
name='Layer',
4042
info='Layer defines the order in which drawobjects are drawn.',
4043
))
4044
4045
def get_drawobjs(self, is_anim=False):
4046
# print 'get_drawobjs'
4047
ids = []
4048
# efficient only if there are few number of different layers
4049
# TODO: use the new sort function of indexed cols
4050
for layer in sorted(set(self.layers.value)):
4051
inds = np.flatnonzero(self.layers.value == layer)
4052
ids += list(self.get_ids(inds))
4053
4054
# print ' ', ids
4055
if not is_anim:
4056
ids_noanim = []
4057
for _id in ids:
4058
# print ' check',_id,self.drawobjects[_id].get_ident(),self.drawobjects[_id].get_name(),self.drawobjects[_id].get_ident().count('anim')
4059
if self.drawobjects[_id].get_ident().count('anim') == 0:
4060
ids_noanim.append(_id)
4061
# print ' ids_noanim',ids_noanim
4062
return self.drawobjects[ids_noanim]
4063
else:
4064
return self.drawobjects[ids] # .value.values()
4065
# return self.drawobjects.value.values()
4066
4067
def has_drawobj_with_ident(self, ident):
4068
return self.idents.has_index(ident)
4069
4070
def get_drawobj_by_ident(self, ident):
4071
if self.has_drawobj_with_ident(ident):
4072
_id = self.idents.get_id_from_index(ident)
4073
return self.drawobjects[_id]
4074
else:
4075
None
4076
4077
def add_drawobj(self, drawobj, layer=0):
4078
id_drawobj = self.add_row(drawobjects=drawobj,
4079
idents=drawobj.get_ident(),
4080
layers=layer,
4081
)
4082
return id_drawobj
4083
4084
def del_drawobj_by_ident(self, ident):
4085
if self.idents.has_index(ident):
4086
_id = self.idents.get_id_from_index(ident)
4087
self.del_row(_id)
4088
return True
4089
else:
4090
return False
4091
4092
4093
class OGLnavcanvas(wx.Panel):
4094
"""
4095
Canvas with some navigation tools.
4096
"""
4097
4098
def __init__(self, parent,
4099
mainframe=None,
4100
size=wx.DefaultSize,
4101
):
4102
4103
wx.Panel.__init__(self, parent, -1)
4104
box = wx.BoxSizer(wx.VERTICAL)
4105
#box.Add((20, 30))
4106
#keys = buttonDefs.keys()
4107
# keys.sort()
4108
# for k in keys:
4109
# text = buttonDefs[k][1]
4110
# btn = wx.Button(self, k, text)
4111
# box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15)
4112
# self.Bind(wx.EVT_BUTTON, self.OnButton, btn)
4113
#btn = wx.Button(self, 1, "test")
4114
#box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15)
4115
4116
# With this enabled, you see how you can put a GLCanvas on the wx.Panel
4117
# if 1:
4118
c = OGLcanvas(self, mainframe=mainframe)
4119
# important to give a value
4120
c.SetMinSize((200, 200))
4121
self._canvas = c
4122
4123
# navigation bar
4124
self._navbar = self.make_navbar()
4125
4126
# compose navcanvas window
4127
#box.Add(self._canvas,1,wx.GROW)#
4128
box.Add(self._canvas, 1, wx.EXPAND)
4129
box.Add(self._navbar, 0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4) # from NaviPanelTest
4130
4131
#box.Add(c, 0, wx.ALIGN_CENTER|wx.ALL, 15)
4132
#box.Add(c, 0, wx.EXPAND)
4133
# sizer.Add(self._toolspanel,0,wx.EXPAND)
4134
4135
self.SetAutoLayout(True)
4136
self.SetSizer(box)
4137
#self.Bind(wx.EVT_SIZE, self.OnSize)
4138
4139
# def OnSize(self, event):
4140
# self.Show(show=True, recursive=True)
4141
4142
def get_canvas(self):
4143
return self._canvas
4144
4145
def make_navbar(self):
4146
"""
4147
Initialize toolbar which consist of navigation buttons
4148
"""
4149
bottonsize = (16, 16)
4150
bottonborder = 10
4151
toolbarborder = 1
4152
4153
# toolbar
4154
4155
##
4156
navbar = wx.BoxSizer(wx.HORIZONTAL)
4157
4158
bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'gtk_fit_zoom_24px.png'), wx.BITMAP_TYPE_PNG)
4159
b = wx.BitmapButton(self, -1, bitmap, bottonsize)
4160
b.SetToolTipString("Zoom to fit")
4161
self.Bind(wx.EVT_BUTTON, self.on_zoom_tofit, b)
4162
navbar.Add(b, flag=wx.ALL, border=toolbarborder) # ,border=toolbarborder ,flag=wx.ALL, # 0, wx.ALL, 5
4163
4164
bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'gtk_in_zoom_24px.png'), wx.BITMAP_TYPE_PNG)
4165
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4166
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4167
b.SetToolTipString("Zoom in")
4168
self.Bind(wx.EVT_BUTTON, self.on_zoom_in, b)
4169
navbar.Add(b, flag=wx.ALL, border=toolbarborder)
4170
4171
bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'gtk_out_zoom_24px.png'), wx.BITMAP_TYPE_PNG)
4172
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4173
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4174
b.SetToolTipString("Zoom out")
4175
self.Bind(wx.EVT_BUTTON, self.on_zoom_out, b)
4176
navbar.Add(b, flag=wx.ALL, border=toolbarborder)
4177
4178
bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'icon_select_components.png'), wx.BITMAP_TYPE_PNG)
4179
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4180
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4181
b.SetToolTipString("Select drawing components")
4182
#b = wx.Button(self, label="Show/Hide")
4183
self.Bind(wx.EVT_BUTTON, self.popup_showhide, b)
4184
navbar.Add(b)
4185
# navbar.AddStretchSpacer()
4186
# navbar.AddSpacer(3)
4187
4188
self.coordsdisplay = wx.StaticText(self, -1, 'x,y', style=wx.TE_RIGHT)
4189
navbar.Add(self.coordsdisplay, wx.ALL | wx.EXPAND, 5, border=toolbarborder) # ,flag=wx.RIGHT no effect??
4190
# self.path = wx.TextCtrl(self, -1,'Try me', style=wx.TE_RIGHT)#size=(-1, -1))#,size=(300, -1))
4191
#self.path.Bind(wx.EVT_CHAR, self.on_test)
4192
#navbar.Add(self.path,1, wx.EXPAND, border=toolbarborder)
4193
4194
#b.Bind(wx.EVT_BUTTON, self.popup_showhide)
4195
4196
#b=wx.Button(self, wx.wx.ID_ZOOM_IN)
4197
#b.SetToolTipString("Zoom in")
4198
#self.Bind(wx.EVT_BUTTON, self.on_test, b)
4199
#navbar.Add(b, flag=wx.ALL, border=toolbarborder)
4200
4201
#bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_FORWARD,wx.ART_TOOLBAR)
4202
# b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4203
# (bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4204
#b.SetToolTipString("Go forward in browser history.")
4205
#self.Bind(wx.EVT_BUTTON, self.on_test, b)
4206
#navbar.Add(b,0, wx.EXPAND, border=toolbarborder)
4207
# bottons.append(b)
4208
4209
# self.add_tool(
4210
# 'home',self.on_go_home,
4211
# wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR, tsize),
4212
# 'show panel of root instance')
4213
4214
# self.toolbar.AddSeparator()
4215
4216
# panel.SetAutoLayout(True)
4217
# panel.SetSizer(buttons)
4218
4219
navbar.Fit(self)
4220
return navbar
4221
4222
def display_coords(self, coords):
4223
# self.coordsdisplay.SetLabel(str(coords[0])+','+str(coords[1]))
4224
self.coordsdisplay.SetLabel('%8.3f,%8.3f' % (coords[0], coords[1]))
4225
4226
def get_navbar(self):
4227
return self._navbar
4228
4229
def on_zoom_tofit(self, event=None):
4230
self._canvas.zoom_tofit()
4231
if event:
4232
event.Skip()
4233
4234
def on_zoom_out(self, event=None):
4235
self._canvas.zoom_out()
4236
if event:
4237
event.Skip()
4238
4239
def on_zoom_in(self, event=None):
4240
self._canvas.zoom_in()
4241
if event:
4242
event.Skip()
4243
4244
def popup_showhide(self, event):
4245
#btn = event.GetEventObject()
4246
drawing = self._canvas.get_drawing()
4247
4248
# Create the popup menu
4249
self._menu_showhide = AgilePopupMenu(self)
4250
if drawing:
4251
for drawobj in drawing.get_drawobjs():
4252
# print ' path=',drawobj.get_name(),drawobj.is_visible()
4253
self._menu_showhide.append_item(
4254
drawobj.get_name(),
4255
self.showhide_drawobjs,
4256
info='Show/hide '+drawobj.get_name(),
4257
check=drawobj.is_visible(),
4258
)
4259
4260
self.PopupMenu(self._menu_showhide)
4261
self._menu_showhide.Destroy()
4262
event.Skip()
4263
4264
def showhide_drawobjs(self, event):
4265
# print 'showhide_drawobjs'
4266
drawing = self._canvas.get_drawing()
4267
if drawing:
4268
for drawobj in drawing.get_drawobjs():
4269
menuitem = self._menu_showhide.get_menuitem(drawobj.get_name())
4270
# print ' set_visible=',drawobj.get_name(),menuitem.IsChecked()
4271
drawobj.set_visible(menuitem.IsChecked())
4272
4273
self._canvas.draw()
4274
event.Skip()
4275
4276
def on_test(self, event=None):
4277
print 'this is a test'
4278
4279
4280
class OGLcanvas(glcanvas.GLCanvas):
4281
def __init__(self, parent, mainframe=None):
4282
if mainframe is None:
4283
self._mainframe = parent
4284
else:
4285
self._mainframe = mainframe
4286
4287
attribList = (glcanvas.WX_GL_RGBA, # RGBA
4288
glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered
4289
glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit
4290
glcanvas.GLCanvas.__init__(self, parent, attribList=attribList)
4291
self.init = False
4292
4293
self.context = glcanvas.GLContext(self)
4294
4295
self.xRotate = 0.
4296
self.yRotate = 0.
4297
self.zRotate = 0.
4298
4299
self.xTrans = 0.
4300
self.yTrans = 0.
4301
4302
# initial mouse position
4303
self.lastx = self.x = 30
4304
self.lasty = self.y = 30
4305
self.size = None
4306
4307
# gui event binding
4308
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
4309
self.Bind(wx.EVT_SIZE, self.OnSize)
4310
self.Bind(wx.EVT_PAINT, self.OnPaint)
4311
4312
# mouse event binding
4313
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
4314
self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDclick)
4315
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
4316
self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
4317
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
4318
self.Bind(wx.EVT_MOTION, self.OnMotion)
4319
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
4320
4321
#
4322
self.action = ""
4323
4324
# 2D geom specific
4325
self.eyex = 0.0
4326
self.eyey = 0.0
4327
self.eyez = -30000.0 # -9.0
4328
4329
self.centerx = 0.0
4330
self.centery = 0.0
4331
self.centerz = 0.0
4332
4333
self.upx = -1.0
4334
self.upy = 0.0
4335
self.upz = 0.0
4336
4337
self.g_Width = 600
4338
self.g_Height = 600
4339
4340
self.g_nearPlane = 10.0 # 10.
4341
self.g_farPlane = 10.0**8 # 10.0**8 #10000.
4342
4343
self.pos_start = (0.0, 0.0)
4344
self.trans_start = (0.0, 0.0)
4345
4346
self.resetView(is_draw=False)
4347
4348
self._tool = None
4349
self._drawing = None
4350
# self.Parent.Fit()
4351
# wx.CallAfter(self.Parent.Fit)
4352
# wx.CallAfter(self.OnSize)
4353
# self.Show()
4354
# self.SetCurrent(self.context)# too e
4355
4356
def polarView(self):
4357
glTranslatef(self.trans[1], 0.0, 0.0)
4358
glTranslatef(0.0, -self.trans[0], 0.0)
4359
4360
glRotatef(-self.zRotate, 0.0, 0.0, 1.0)
4361
glRotatef(-self.xRotate, 1.0, 0.0, 0.0)
4362
glRotatef(-self.yRotate, 0.0, 1.0, 0.0)
4363
4364
def OnEraseBackground(self, event):
4365
pass # Do nothing, to avoid flashing on MSW.
4366
4367
def OnSize(self, event):
4368
wx.CallAfter(self.DoSetViewport)
4369
event.Skip()
4370
# self.DoSetViewport()
4371
4372
def DoSetViewport(self):
4373
# self.Show()
4374
size = self.size = self.GetClientSize()
4375
# print 'DoSetViewport',size.width, size.height,self.IsShown()
4376
# if self.IsShown():
4377
4378
# sufficient to call SetCurrent in OnPaint
4379
# try:
4380
# #if self.context is not None:
4381
# #self.SetCurrent(self.context)
4382
# pass
4383
# except:
4384
# print 'WARNING in DoSetViewport: caoon set context'
4385
#glViewport(0, 0, size.width, size.height)
4386
self.OnReshape(size.width, size.height)
4387
# self.OnPaint()
4388
4389
def set_color_background(self, color):
4390
glClearColor(color[0], color[1], color[2], color[3])
4391
self.draw()
4392
4393
def OnReshape(self, width, height):
4394
"""Reshape the OpenGL viewport based on the dimensions of the window."""
4395
#global g_Width, g_Height
4396
self.g_Width = width
4397
self.g_Height = height
4398
glViewport(0, 0, self.g_Width, self.g_Height)
4399
4400
def OnPaint(self, event=None):
4401
# print 'OnPaint',self.IsShown()
4402
dc = wx.PaintDC(self)
4403
self.SetCurrent(self.context)
4404
if not self.init:
4405
self.InitGL()
4406
self.init = True
4407
self.OnDraw()
4408
# err self.SendSizeEventToParent()
4409
#del dc
4410
4411
def InitGL(self):
4412
glClearColor(0, 0, 0, 1)
4413
4414
def get_intersection(self, v_near, v_far):
4415
# 150918
4416
# idea from http://www.bfilipek.com/2012/06/select-mouse-opengl.html
4417
# https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection
4418
d = -v_near + v_far
4419
4420
t = -v_near[2]/d[2]
4421
v_inter = v_near+t*d
4422
4423
return v_inter
4424
4425
def unproject_event(self, event):
4426
return self.unproject(event.GetPosition())[0:2]
4427
4428
def unproject(self, pos_display):
4429
"""Get the world coordinates for viewCoordinate for the event
4430
"""
4431
# print 'unproject',pos_display
4432
x = pos_display[0]
4433
y = self.g_Height-pos_display[1]
4434
4435
modelviewmatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
4436
projectionmatrix = glGetDoublev(GL_PROJECTION_MATRIX)
4437
viewport = glGetInteger(GL_VIEWPORT)
4438
4439
z = 0.0
4440
worldCoordinate_near = np.array(gluUnProject(
4441
x, y, z,
4442
modelviewmatrix,
4443
projectionmatrix,
4444
viewport,), dtype=np.float32)
4445
4446
z = 1.0
4447
worldCoordinate_far = np.array(gluUnProject(
4448
x, y, z,
4449
modelviewmatrix,
4450
projectionmatrix,
4451
viewport,), dtype=np.float32)
4452
4453
v_inter = self.get_intersection(worldCoordinate_near, worldCoordinate_far)
4454
# print ' world coords v_inter',v_inter
4455
return v_inter
4456
4457
def project(self, vertex):
4458
"""
4459
http://stackoverflow.com/questions/3792481/how-to-get-screen-coordinates-from-a-3d-point-opengl
4460
"""
4461
modelviewmatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
4462
projectionmatrix = glGetDoublev(GL_PROJECTION_MATRIX)
4463
viewport = glGetInteger(GL_VIEWPORT)
4464
4465
coords = np.array(gluProject(vertex[0], vertex[1], vertex[2],
4466
modelviewmatrix, projectionmatrix,
4467
viewport))
4468
4469
coords[1] = self.g_Height - coords[1]
4470
# print 'project',coords
4471
4472
return coords
4473
4474
def OnDraw(self, *args, **kwargs):
4475
"""Draw the window."""
4476
4477
# print 'OGLCanvas.draw id(self._drawing)',id(self._drawing)
4478
# Clear frame buffer and depth buffer
4479
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
4480
# Set up viewing transformation, looking down -Z axis
4481
if self._drawing is None:
4482
self.SwapBuffers()
4483
return
4484
4485
glLoadIdentity()
4486
gluLookAt(self.eyex, self.eyey, self.eyez, self.centerx, self.centery,
4487
self.centerz, self.upx, self.upy, self.upz) # -.1,0,0
4488
4489
# Set perspective (also zoom)
4490
glMatrixMode(GL_PROJECTION)
4491
glLoadIdentity()
4492
# the window corner OpenGL coordinates are (-+1, -+1)
4493
glOrtho(-1, 1, 1, -1, -1, 1)
4494
4495
aspect = float(self.g_Width)/float(self.g_Height)
4496
4497
gluPerspective(self.zoom, aspect, self.g_nearPlane, self.g_farPlane)
4498
glMatrixMode(GL_MODELVIEW)
4499
self.polarView()
4500
4501
# resolution in GL unit per scren pixel
4502
#resolution = self.get_resolution()
4503
# print ' get_resolution',resolution
4504
4505
# draw actual scene
4506
# if self._drawing:
4507
# self._drawing.print_attrs()
4508
for drawobj in self._drawing.get_drawobjs(is_anim=True):
4509
#checkobj = self._drawing.get_drawobj_by_ident(drawobj.ident)
4510
# if checkobj is not None:
4511
# print '\n draw.drawobj',drawobj.ident, checkobj.ident
4512
# else:
4513
# print '\n draw.drawobj',drawobj.ident, checkobj,self._drawing.has_drawobj_with_ident(drawobj.ident)
4514
drawobj.draw() # resolution)
4515
4516
self.SwapBuffers()
4517
4518
def draw(self, *args, **kwargs):
4519
# print 'draw',self.IsShown()
4520
# self.Show() # does not prevent error in SetCurrent
4521
try:
4522
self.SetCurrent(self.context)
4523
self.OnDraw(*args, **kwargs)
4524
# print 'draw',self.lastx,self.lasty,self.x,self.y
4525
except:
4526
print 'WARNING in draw: unable to set context'
4527
4528
def set_drawing(self, drawing):
4529
if self._drawing != drawing:
4530
4531
# if self._tool is not None:
4532
# self._tool.force_deactivation()
4533
4534
del self._drawing
4535
self._drawing = drawing
4536
# self.draw()
4537
4538
def activate_tool(self, tool):
4539
# called from tool
4540
self._tool = tool
4541
4542
def deactivate_tool(self):
4543
# called from tool
4544
4545
# print 'deactivate_tool',self._tool.format_ident()
4546
# make sure cursor gets back to normal
4547
self.SetCursor(wx.NullCursor)
4548
4549
# self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
4550
self._tool = None
4551
self.draw()
4552
4553
def get_tool(self):
4554
return self._tool
4555
4556
def get_drawing(self):
4557
return self._drawing
4558
4559
def resetView(self, is_draw=True):
4560
self.zoom = 65.
4561
4562
self.xRotate = 180.
4563
self.yRotate = 180.
4564
self.zRotate = -90.0
4565
self.trans = (0.0, 0.0)
4566
4567
if is_draw:
4568
self.draw()
4569
4570
def on_key_down(self, event):
4571
is_draw = False
4572
# print 'on_key_down',event.KeyCode(),type(event.KeyCode())
4573
if event.KeyCode() == 'x':
4574
self.xRotate += 5.0
4575
is_draw |= True
4576
4577
if is_draw:
4578
self.draw()
4579
event.Skip()
4580
4581
def get_resolution(self):
4582
"""
4583
Resolution in GL unit per scren pixel
4584
"""
4585
if (self.g_Width == 0) & (self.g_Height == 0):
4586
# there is no window space
4587
return 1.0
4588
4589
v_top = self.unproject((0.5*self.g_Width, 0))
4590
v_bot = self.unproject((0.5*self.g_Width, self.g_Height))
4591
4592
v_left = self.unproject((0, 0.5 * self.g_Height))
4593
v_right = self.unproject((self.g_Width, 0.5*self.g_Height))
4594
4595
dy = np.abs(v_bot[1]-v_top[1])
4596
dx = np.abs(v_right[1]-v_left[1])
4597
4598
if dx > dy:
4599
return dx/self.g_Width
4600
else:
4601
return dy/self.g_Height
4602
4603
def zoom_tofit(self, event=None, is_draw=True):
4604
# print 'zoom_tofit',is_draw
4605
#p = self._canvas.unproject_event(event)
4606
#vetrex = np.array([p[0], p[1], 0.0, 1.0],float)
4607
#p_screen = self._canvas.project(vetrex)
4608
# print 'SelectTool.on_left_down (px,py)=',p
4609
# print ' (x,y)=',event.GetPosition(),p_screen
4610
self.resetView()
4611
4612
vv_min, vv_max = self.get_boundingbox()
4613
dv = vv_max - vv_min
4614
4615
# print 'vv_min',vv_min
4616
# print 'vv_max',vv_max
4617
4618
p_min = self.project(vv_min)
4619
p_max = self.project(vv_max)
4620
4621
# print 'p_min',p_min
4622
# print 'p_max',p_max
4623
4624
dp = np.abs(np.array(p_max-p_min, float))
4625
4626
# print ' dp',dp,dp==np.nan,np.nan
4627
if np.isnan(np.sum(dp)):
4628
return
4629
4630
window = np.array([self.g_Width, self.g_Height], float)
4631
zoomfactor = 0.8*np.min(window/dp[:2])
4632
4633
# print ' zoomfactor,zoom',zoomfactor,self.zoom
4634
4635
self.zoom /= zoomfactor
4636
# print ' zoomfactor',zoomfactor,self.zoom
4637
4638
self.draw()
4639
#vv_min, vv_max = self.get_boundingbox()
4640
4641
# lowerleft corner
4642
vv_target = self.unproject((0.0, self.g_Height))
4643
4644
# print ' vv_min',vv_min
4645
# print ' vv_target',vv_target
4646
# print ' trans',self.trans
4647
dv = 0.9*vv_target-vv_min
4648
4649
# print ' dv',dv
4650
newtrans = np.array(self.trans) + dv[:2]
4651
self.trans = tuple(newtrans)
4652
# print ' trans',self.trans
4653
self.draw()
4654
4655
def get_boundingbox(self):
4656
drawing = self.get_drawing()
4657
vv_min = np.inf * np.ones((1, 3), float)
4658
vv_max = -np.inf * np.ones((1, 3), float)
4659
if drawing:
4660
for drawobj in drawing.get_drawobjs():
4661
bb = drawobj.get_boundingbox()
4662
if bb is not None:
4663
v_min, v_max = bb
4664
# print ' v_min',v_min
4665
# print ' v_max',v_max
4666
vv_min = np.concatenate((vv_min, v_min.reshape(1, 3)), 0)
4667
vv_max = np.concatenate((vv_max, v_max.reshape(1, 3)), 0)
4668
# print ' vv_min',vv_min
4669
# print ' vv_max',vv_max
4670
vv_min = np.min(vv_min, 0)
4671
vv_max = np.max(vv_max, 0)
4672
return vv_min, vv_max
4673
4674
def zoom_in(self, event=None, is_draw=True):
4675
self.zoom *= 0.9
4676
if is_draw:
4677
self.draw()
4678
4679
def zoom_out(self, event=None, is_draw=True):
4680
self.zoom *= 1.1
4681
if is_draw:
4682
self.draw()
4683
4684
def OnLeftDown(self, event, is_draw=False):
4685
# print 'GLCanvas.OnLeftDown',self._tool
4686
is_control_down = event.ControlDown() # | event.RawControlDown() | event.MetaDown()
4687
if (is_control_down & event.ShiftDown()) & (self.action == ''):
4688
self.action = 'drag'
4689
self.BeginGrap(event)
4690
event.Skip()
4691
4692
elif self._tool is not None:
4693
is_draw = self._tool.on_left_down(event)
4694
4695
if is_draw:
4696
self.draw()
4697
event.Skip()
4698
4699
def OnLeftDclick(self, event, is_draw=False):
4700
if self._tool is not None:
4701
is_draw = self._tool.on_left_dclick(event)
4702
4703
if is_draw:
4704
self.draw()
4705
event.Skip()
4706
4707
def OnLeftUp(self, event, is_draw=False):
4708
4709
if self.action == 'drag':
4710
self.EndGrap(event)
4711
self.action == ''
4712
event.Skip()
4713
4714
elif self._tool is not None:
4715
is_draw = self._tool.on_left_up(event)
4716
4717
if is_draw:
4718
self.draw()
4719
event.Skip()
4720
4721
def OnRightDown(self, event, is_draw=False):
4722
if self._tool is not None:
4723
is_draw = self._tool.on_right_down(event)
4724
4725
if is_draw:
4726
self.draw()
4727
event.Skip()
4728
4729
def OnRightUp(self, event, is_draw=False):
4730
4731
if self._tool is not None:
4732
is_draw = self._tool.on_right_up(event)
4733
4734
if is_draw:
4735
self.draw()
4736
event.Skip()
4737
4738
def OnMotion(self, event, is_draw=False):
4739
# print 'OnMotion',event.GetPosition()
4740
self.GetParent().display_coords(self.unproject_event(event))
4741
4742
if (event.ControlDown() & event.ShiftDown() & (self.action == 'drag')):
4743
self.MoveGrap(event)
4744
is_draw |= True
4745
event.Skip()
4746
4747
elif (self.action == 'drag'):
4748
self.EndGrap(event)
4749
is_draw |= True
4750
self.action == ''
4751
event.Skip()
4752
4753
elif self._tool is not None:
4754
is_draw |= self._tool.on_motion(event)
4755
4756
if is_draw:
4757
self.draw()
4758
4759
def BeginGrap(self, event):
4760
# http://www.wxpython.org/docs/api/wx.Cursor-class.html
4761
self._cursor_last = self.GetCursor()
4762
self.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
4763
self.pos_start = event.GetPosition()
4764
self.trans_start = self.trans
4765
# print 'BeginGrap',self.trans
4766
4767
def MoveGrap(self, event):
4768
4769
x, y = self.unproject(event.GetPosition())[0:2]
4770
x0, y0 = self.unproject(self.pos_start)[0:2]
4771
4772
self.trans = (self.trans_start[0] + (x-x0), self.trans_start[1] + (y-y0))
4773
# print 'MoveGrap',self.trans, x,y
4774
4775
def EndGrap(self, event):
4776
# print 'EndGrap'
4777
self.SetCursor(self._cursor_last)
4778
self.action = ''
4779
4780
def OnWheel(self, event, is_draw=False):
4781
#EventType = FloatCanvas.EVT_FC_MOUSEWHEEL
4782
#
4783
Rot = event.GetWheelRotation()
4784
# print 'OnWheel!!',Rot,event.ControlDown(),event.ShiftDown()
4785
if (not event.ShiftDown()) & event.ControlDown(): # event.ControlDown(): # zoom
4786
if Rot < 0:
4787
self.zoom_in(is_draw=False)
4788
else:
4789
self.zoom_out(is_draw=False)
4790
is_draw |= True
4791
4792
if (event.ShiftDown()) & event.ControlDown(): # event.ControlDown(): # zoom
4793
if Rot < 0:
4794
self.xRotate -= 5.0
4795
else:
4796
self.xRotate += 5.0
4797
is_draw |= True
4798
4799
elif self._tool is not None:
4800
is_draw |= self._tool.on_wheel(event)
4801
self.draw()
4802
event.Skip()
4803
4804
if is_draw:
4805
self.draw()
4806
event.Skip()
4807
4808
4809
class OGLcanvasTools(ToolsPanel):
4810
"""
4811
Shows a toolpallet with different tools and an options panel.
4812
Here tools are added which
4813
"""
4814
4815
def __init__(self, parent):
4816
ToolsPanel.__init__(self, parent, n_buttoncolumns=3, size=wx.DefaultSize)
4817
4818
# add ainitial tool
4819
self.add_initial_tool(SelectTool(self))
4820
4821
# self.add_tool(HandleTool(self))
4822
self.add_tool(StretchTool(self))
4823
self.add_tool(MoveTool(self))
4824
4825
self.add_tool(AddLineTool(self))
4826
self.add_tool(AddCircleTool(self))
4827
self.add_tool(AddPolylineTool(self))
4828
self.add_tool(AddPolygonTool(self))
4829
4830
self.add_tool(DeleteTool(self))
4831
4832
self.add_tool(ConfigureTool(self))
4833
# more tools can be added later...
4834
4835
4836
class OGleditor(wx.Panel):
4837
4838
def __init__(self, parent,
4839
mainframe=None,
4840
size=wx.DefaultSize,
4841
is_menu=False, # create menu items
4842
Debug=0,
4843
):
4844
4845
self._drawing = None
4846
4847
# if drawing is not None:....
4848
self.prefix_anim = 'anim_'
4849
self.layer_anim = 1000.0
4850
4851
wx.Panel.__init__(self, parent, wx.ID_ANY, size=size)
4852
sizer = wx.BoxSizer(wx.HORIZONTAL)
4853
4854
self._mainframe = mainframe
4855
4856
# initialize GL canvas
4857
navcanvas = OGLnavcanvas(self, mainframe)
4858
#self._canvas = OGLcanvas(self)
4859
self._canvas = navcanvas.get_canvas()
4860
4861
# compose tool pallet here
4862
self._toolspanel = OGLcanvasTools(self)
4863
4864
# compose editor window
4865
4866
# works but toolpanel changes size!!!
4867
# sizer.Add(self._toolspanel,0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4)# from NaviPanelTest
4868
# sizer.Add(navcanvas,1,wx.GROW)
4869
4870
# print 'OGleditor!!!!!!!!!!!!!!!!!!!'
4871
4872
# 2.8 OK for 3.0 also
4873
sizer.Add(self._toolspanel, 0, wx.EXPAND)
4874
sizer.Add(navcanvas, 1, wx.EXPAND)
4875
4876
self.SetAutoLayout(True)
4877
4878
# finish panel setup
4879
self.SetSizer(sizer)
4880
# sizer.Fit(self)
4881
# self.Layout()
4882
4883
# no use:
4884
#wx.EVT_SIZE(self, self.on_size)
4885
4886
def on_test(self, event=None, drawing=None):
4887
print '\non_test'
4888
4889
if drawing is None:
4890
drawing = OGLdrawing()
4891
vertices = np.array([
4892
[[0.0, 0.0, 0.0], [0.2, 0.0, 0.0]], # 0 green
4893
[[0.0, 0.0, 0.0], [0.0, 0.9, 0.0]], # 1 red
4894
])
4895
4896
colors = np.array([
4897
[0.0, 0.9, 0.0, 0.9], # 0
4898
[0.9, 0.0, 0.0, 0.9], # 1
4899
])
4900
4901
colors2 = np.array([
4902
[0.5, 0.9, 0.5, 0.5], # 0
4903
[0.9, 0.5, 0.9, 0.5], # 1
4904
])
4905
colors2o = np.array([
4906
[0.8, 0.9, 0.8, 0.9], # 0
4907
[0.9, 0.8, 0.9, 0.9], # 1
4908
])
4909
4910
4911
# -------------------------------------------------------------------------------
4912
4913
if 1:
4914
lines = Lines('lines', drawing)
4915
lines.add_drawobjs(vertices, colors)
4916
drawing.add_drawobj(lines)
4917
4918
4919
# -------------------------------------------------------------------------------
4920
4921
if 1:
4922
rectangles = Rectangles('rectangles', drawing,
4923
is_fill=True,
4924
is_outline=True)
4925
4926
colors = np.array([
4927
[0.2, 0.9, 0.0, 0.9], # 0
4928
[0.9, 0.2, 0.0, 0.9], # 1
4929
])
4930
4931
colors2 = np.array([
4932
[0.9, 0.9, 0.5, 0.3], # 0
4933
[0.9, 0.9, 0.5, 0.3], # 1
4934
])
4935
4936
rectangles.add_drawobjs([[3.0, 0.0, 0.0], [0.0, 3.0, 0.0]], # offsets
4937
widths=[1.0, 1.6],
4938
lengths=[2.0, 0.4],
4939
rotangles_xy=[0, 0.5],
4940
colors=colors,
4941
colors_fill=colors2)
4942
drawing.add_drawobj(rectangles)
4943
4944
4945
# -------------------------------------------------------------------------------
4946
if 1:
4947
fancylines = Fancylines('fancylines', drawing,
4948
arrowstretch=1.0,
4949
is_lefthalf=True,
4950
is_righthalf=True
4951
)
4952
4953
colors_fancy = np.array([
4954
[0.0, 0.9, 0.0, 0.9], # 0
4955
# [0.9,0.0,0.0,0.9], # 1
4956
])
4957
vertices_fancy = np.array([
4958
[[0.0, -1.0, 0.0], [2, -1.0, 0.0]], # 0 green
4959
# [[0.0,-1.0,0.0],[0.0,-5.0,0.0]],# 1 red
4960
])
4961
4962
widths = [0.5,
4963
# 0.3,
4964
]
4965
# print ' vertices_fancy\n',vertices_fancy
4966
# FLATHEAD = 0
4967
#BEVELHEAD = 1
4968
#TRIANGLEHEAD = 2
4969
#ARROWHEAD = 3
4970
fancylines.add_drawobjs(vertices_fancy,
4971
widths, # width
4972
colors_fancy,
4973
beginstyles=[TRIANGLEHEAD, ],
4974
endstyles=[TRIANGLEHEAD, ],
4975
)
4976
drawing.add_drawobj(fancylines, layer=10)
4977
# -------------------------------------------------------------------------------
4978
if 1:
4979
polylines = Polylines('polylines', drawing,
4980
joinstyle=FLATHEAD,
4981
arrowstretch=1.0,
4982
is_lefthalf=True,
4983
is_righthalf=True
4984
)
4985
colors_poly = np.array([
4986
[0.0, 0.8, 0.5, 0.9], # 0
4987
[0.8, 0.0, 0.5, 0.9], # 1
4988
])
4989
4990
vertices_poly = np.array([
4991
[[0.0, 2.0, 0.0], [5.0, 2.0, 0.0], [5.0, 7.0, 0.0], [10.0, 7.0, 0.0]], # 0 green
4992
[[0.0, -2.0, 0.0], [-2.0, -2.0, 0.0]], # 1 red
4993
], np.object)
4994
4995
widths = [0.5,
4996
0.3,
4997
]
4998
# print ' vertices_poly\n',vertices_poly
4999
polylines.add_drawobjs(vertices_poly,
5000
widths, # width
5001
colors_poly,
5002
beginstyles=[TRIANGLEHEAD, TRIANGLEHEAD],
5003
endstyles=[TRIANGLEHEAD, TRIANGLEHEAD])
5004
drawing.add_drawobj(polylines, layer=-2)
5005
5006
# -------------------------------------------------------------------------------
5007
if 1:
5008
polygons = Polygons('polygons', drawing, linewidth=5)
5009
colors_poly = np.array([
5010
[0.0, 0.9, 0.9, 0.9], # 0
5011
[0.8, 0.2, 0.2, 0.9], # 1
5012
])
5013
5014
vertices_poly = [
5015
[[0.0, 2.0, 0.0], [5.0, 2.0, 0.0], [5.0, 7.0, 0.0], ], # 0 green
5016
[[0.0, -2.0, 0.0], [-2.0, -2.0, 0.0], [-2.0, 0.0, 0.0]], # 1 red
5017
]
5018
5019
print ' vertices_polygon\n', vertices_poly
5020
polygons.add_drawobjs(vertices_poly,
5021
colors_poly)
5022
polygons.add_drawobj([[5.0, -2.0, 0.0], [3.0, -2.0, 0.0], [3.0, 0.0, 0.0]],
5023
[0.8, 0.2, 0.8, 0.9])
5024
drawing.add_drawobj(polygons)
5025
5026
5027
# -------------------------------------------------------------------------------
5028
5029
if 1:
5030
circles = Circles('circles', drawing,
5031
is_fill=False, # Fill objects,
5032
is_outline=True, # show outlines
5033
)
5034
circles.add_drawobjs([[0.0, 0.0, 0.0], [1.0, 0.5, 0.0]], [0.5, 0.25], colors2o, colors2)
5035
drawing.add_drawobj(circles)
5036
5037
# canvas.zoom_tofit()
5038
# wx.CallAfter(canvas.zoom_tofit)
5039
self.add_drawobjs_anim(drawing)
5040
self.set_drawing(drawing)
5041
if event:
5042
event.Skip()
5043
5044
def get_canvas(self):
5045
# DEPRICATED: canvas should not be needed outside netwdit
5046
# this is used mainly by the tools to know on which canvas to operate on
5047
# if multiple canvas, use the one with focus
5048
return self._canvas
5049
5050
def draw(self):
5051
5052
self._canvas.draw()
5053
# in the future there can be the same drawing on multiple canvases
5054
5055
def get_toolbox(self):
5056
return self._toolspanel
5057
5058
def add_toolclass(self, Toolclass, **kwargs):
5059
"""
5060
Add a new Toolclas to the tool-panel on the right side of the editor
5061
"""
5062
self.get_toolbox().add_toolclass(Toolclass, **kwargs)
5063
5064
def set_drawing(self, drawing):
5065
# self._toolspanel.reset_initial_tool()
5066
# here ad some additional drawing objects for animation
5067
# self.add_drawobjs_anim(drawing)
5068
self._drawing = drawing
5069
self._canvas.set_drawing(drawing)
5070
self._toolspanel.reset_initial_tool()
5071
5072
# wx.CallAfter(self._canvas.zoom_tofit)
5073
5074
def get_drawing(self):
5075
return self._drawing # self._canvas.get_drawing()
5076
5077
def add_drawobjs_anim(self, drawing=None):
5078
5079
if drawing is None:
5080
drawing = self._drawing
5081
drawobjs_anim = [Lines(self.prefix_anim+'lines', drawing,
5082
linewidth=1),
5083
5084
Rectangles(self.prefix_anim+'rectangles', drawing,
5085
linewidth=1,
5086
),
5087
5088
Fancylines(self.prefix_anim+'fancylines', drawing,
5089
is_lefthalf=True,
5090
is_righthalf=True,
5091
linewidth=1,
5092
),
5093
5094
Lines(self.prefix_anim+'lines', drawing,
5095
linewidth=1),
5096
5097
Polylines(self.prefix_anim+'polylines', drawing,
5098
joinstyle=FLATHEAD,
5099
is_lefthalf=True,
5100
is_righthalf=True,
5101
linewidth=1,
5102
),
5103
5104
Polygons(self.prefix_anim+'polygons', drawing,
5105
linewidth=1),
5106
5107
Circles(self.prefix_anim+'circles', drawing,
5108
is_fill=False, # Fill objects,
5109
is_outline=True, # show outlines
5110
linewidth=1,
5111
),
5112
5113
Triangles(self.prefix_anim+'triangles', drawing,
5114
is_fill=False, # Fill objects,
5115
is_outline=True, # show outlines
5116
linewidth=1,
5117
),
5118
]
5119
5120
for drawobj in drawobjs_anim:
5121
drawing.add_drawobj(drawobj, layer=self.layer_anim)
5122
5123
def get_mainframe(self):
5124
# this is used mainly by the tools to know on which mainframe to operate on
5125
return self._mainframe
5126
5127
# def on_size(self,event=None):
5128
# #print 'on_size',self._toolspanel.GetSize()
5129
#
5130
# if event:
5131
# event.Skip()
5132
5133
5134
if __name__ == '__main__':
5135
###############################################################################
5136
# MAIN FRAME
5137
5138
from mainframe import AgileToolbarFrameMixin
5139
5140
class OGLeditorMainframe(AgileToolbarFrameMixin, wx.Frame):
5141
"""
5142
Simple wx frame with some special features.
5143
"""
5144
5145
def __init__(self, title, pos=wx.DefaultPosition,
5146
size=(1000, 500), style=wx.DEFAULT_FRAME_STYLE,
5147
name='frame'):
5148
5149
# Forcing a specific style on the window.
5150
# Should this include styles passed?
5151
style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
5152
wx.Frame.__init__(self, None, wx.NewId(), title, pos, size=size, style=style, name=name)
5153
self.gleditor = OGleditor(self)
5154
5155
self.Show() # must be here , before putting stuff on canvas
5156
5157
#################################################################
5158
# create the menu bar
5159
5160
self.menubar = AgileMenubar(self)
5161
self.make_menu()
5162
# self.menubar.append_menu('tools')
5163
self.SetMenuBar(self.menubar)
5164
self.on_test()
5165
5166
def make_menu(self, event=None):
5167
self.menubar.append_menu('file')
5168
# self.menubar.append_item('file/test',self.on_test,\
5169
# shortkey='Ctrl+t',info='Draw test objects')
5170
5171
def on_test(self, event=None):
5172
print '\non_test'
5173
vertices = np.array([
5174
[[0.0, 0.0, 0.0], [0.2, 0.0, 0.0]], # 0 green
5175
[[0.0, 0.0, 0.0], [0.0, 0.9, 0.0]], # 1 red
5176
])
5177
5178
colors = np.array([
5179
[0.0, 0.9, 0.0, 0.9], # 0
5180
[0.9, 0.0, 0.0, 0.9], # 1
5181
])
5182
5183
colors2 = np.array([
5184
[0.5, 0.9, 0.5, 0.5], # 0
5185
[0.9, 0.5, 0.9, 0.5], # 1
5186
])
5187
colors2o = np.array([
5188
[0.8, 0.9, 0.8, 0.9], # 0
5189
[0.9, 0.8, 0.9, 0.9], # 1
5190
])
5191
5192
drawing = OGLdrawing()
5193
# -------------------------------------------------------------------------------
5194
5195
if 1:
5196
lines = Lines('lines', drawing)
5197
lines.add_drawobjs(vertices, colors)
5198
drawing.add_drawobj(lines)
5199
5200
# -------------------------------------------------------------------------------
5201
if 1:
5202
triangles = Triangles('triangles', drawing,
5203
is_fill=True,
5204
is_outline=True)
5205
triangles.add_drawobjs(np.array([
5206
[[0.0, 0.0, 0.0], [1.5, 0.0, 0.0], [1.5, 2.5, 0.0]], # 0 green
5207
[[0.0, 0.0, 0.0], [-1.5, -0.9, 0.0], [-1.0, -2.5, 0.0]], # 1 red
5208
]), colors2, colors2o)
5209
drawing.add_drawobj(triangles)
5210
5211
5212
# -------------------------------------------------------------------------------
5213
5214
if 1:
5215
rectangles = Rectangles('rectangles', drawing,
5216
is_fill=True,
5217
is_outline=True)
5218
5219
colors = np.array([
5220
[0.2, 0.9, 0.0, 0.9], # 0
5221
[0.9, 0.2, 0.0, 0.9], # 1
5222
])
5223
5224
colors2 = np.array([
5225
[0.9, 0.9, 0.5, 0.3], # 0
5226
[0.9, 0.9, 0.5, 0.3], # 1
5227
])
5228
5229
rectangles.add_drawobjs([[3.0, 0.0, 0.0], [0.0, 3.0, 0.0]], # offsets
5230
widths=[1.0, 1.6],
5231
lengths=[2.0, 0.4],
5232
rotangles_xy=[0, 0.5],
5233
colors=colors,
5234
colors_fill=colors2)
5235
drawing.add_drawobj(rectangles)
5236
5237
5238
# -------------------------------------------------------------------------------
5239
if 1:
5240
fancylines = Fancylines('fancylines', drawing,
5241
arrowstretch=1.0,
5242
is_lefthalf=True,
5243
is_righthalf=True
5244
)
5245
5246
colors_fancy = np.array([
5247
[0.0, 0.9, 0.0, 0.9], # 0
5248
# [0.9,0.0,0.0,0.9], # 1
5249
])
5250
vertices_fancy = np.array([
5251
[[0.0, -1.0, 0.0], [2, -1.0, 0.0]], # 0 green
5252
# [[0.0,-1.0,0.0],[0.0,-5.0,0.0]],# 1 red
5253
])
5254
5255
widths = [0.5,
5256
# 0.3,
5257
]
5258
# print ' vertices_fancy\n',vertices_fancy
5259
# FLATHEAD = 0
5260
#BEVELHEAD = 1
5261
#TRIANGLEHEAD = 2
5262
#ARROWHEAD = 3
5263
fancylines.add_drawobjs(vertices_fancy,
5264
widths, # width
5265
colors_fancy,
5266
beginstyles=[TRIANGLEHEAD, ],
5267
endstyles=[TRIANGLEHEAD, ],
5268
)
5269
drawing.add_drawobj(fancylines, layer=10)
5270
# -------------------------------------------------------------------------------
5271
if 1:
5272
polylines = Polylines('polylines', drawing,
5273
joinstyle=FLATHEAD,
5274
arrowstretch=1.0,
5275
is_lefthalf=True,
5276
is_righthalf=True
5277
)
5278
colors_poly = np.array([
5279
[0.0, 0.8, 0.5, 0.9], # 0
5280
[0.8, 0.0, 0.5, 0.9], # 1
5281
])
5282
5283
vertices_poly = np.array([
5284
[[0.0, 2.0, 0.0], [5.0, 2.0, 0.0], [5.0, 7.0, 0.0], [10.0, 7.0, 0.0]], # 0 green
5285
[[0.0, -2.0, 0.0], [-2.0, -2.0, 0.0]], # 1 red
5286
], np.object)
5287
5288
widths = [0.5,
5289
0.3,
5290
]
5291
# print ' vertices_poly\n',vertices_poly
5292
polylines.add_drawobjs(vertices_poly,
5293
widths, # width
5294
colors_poly,
5295
beginstyles=[TRIANGLEHEAD, TRIANGLEHEAD],
5296
endstyles=[TRIANGLEHEAD, TRIANGLEHEAD])
5297
drawing.add_drawobj(polylines, layer=-2)
5298
5299
# -------------------------------------------------------------------------------
5300
if 1:
5301
polygons = Polygons('polygons', drawing, linewidth=5)
5302
colors_poly = np.array([
5303
[0.0, 0.9, 0.9, 0.9], # 0
5304
[0.8, 0.2, 0.2, 0.9], # 1
5305
])
5306
5307
vertices_poly = [
5308
[[0.0, 2.0, 0.0], [5.0, 2.0, 0.0], [5.0, 7.0, 0.0], ], # 0 green
5309
[[0.0, -2.0, 0.0], [-2.0, -2.0, 0.0], [-2.0, 0.0, 0.0]], # 1 red
5310
]
5311
5312
print ' vertices_polygon\n', vertices_poly
5313
polygons.add_drawobjs(vertices_poly,
5314
colors_poly)
5315
polygons.add_drawobj([[5.0, -2.0, 0.0], [3.0, -2.0, 0.0], [3.0, 0.0, 0.0]],
5316
[0.8, 0.2, 0.8, 0.9])
5317
drawing.add_drawobj(polygons)
5318
5319
5320
# -------------------------------------------------------------------------------
5321
5322
if 1:
5323
circles = Circles('circles', drawing,
5324
is_fill=False, # Fill objects,
5325
is_outline=True, # show outlines
5326
)
5327
circles.add_drawobjs([[0.0, 0.0, 0.0], [1.0, 0.5, 0.0]], [0.5, 0.25], colors2o, colors2)
5328
drawing.add_drawobj(circles)
5329
5330
# drawing.add_drawobj(testogl.triangles)
5331
# drawing.add_drawobj(testogl.rectangles)
5332
# -------------------------------------------------------------------------------
5333
5334
#canvas = self.gleditor.get_canvas()
5335
# canvas.set_drawing(drawing)
5336
5337
#lines.add_drawobj([[0.0,0.0,0.0],[-0.2,-0.8,0.0]], [0.0,0.9,0.9,0.9])
5338
#circles.add_drawobj([1.5,0.0,0.0],0.6,colors2o[0], colors2[0])
5339
5340
# canvas.zoom_tofit()
5341
# wx.CallAfter(canvas.zoom_tofit)
5342
self.gleditor.add_drawobjs_anim(drawing)
5343
self.gleditor.set_drawing(drawing)
5344
if event:
5345
event.Skip()
5346
5347
def get_objbrowser(self):
5348
return self._objbrowser
5349
5350
class OGLeditorApp(wx.App):
5351
def OnInit(self):
5352
# wx.InitAllImageHandlers()
5353
self.mainframe = OGLeditorMainframe("OGLeditor")
5354
#sumopyicon = wx.Icon(os.path.join(IMAGEDIR,'icon_sumopy.png'),wx.BITMAP_TYPE_PNG, 16,16)
5355
# wx.Frame.SetIcon(self.mainframe,sumopyicon)
5356
# self.mainframe.SetIcon(sumopyicon)
5357
5358
# if True: #len(sys.argv)>=2:
5359
# from lib.net import readNet
5360
# filepath = '/home/joerg/projects/sumopy/bologna/bologna4.net.xml'#sys.argv[1]
5361
# _net = readNet(filepath)
5362
# else:
5363
# _net = None
5364
5365
self.SetTopWindow(self.mainframe)
5366
return True
5367
5368
###########################################################################
5369
# MAINLOOP
5370
5371
if len(sys.argv) == 3:
5372
ident = sys.argv[1]
5373
dirpath = sys.argv[2]
5374
else:
5375
ident = None
5376
dirpath = None
5377
app = OGLeditorApp(0)
5378
5379
if 0: # len(noplugins)>0:
5380
_msg = """The following plugins could not be plugged in:\n\n """ + noplugins[:-2] +\
5381
"""\n\nIf you like to use these plugins, please check messages on console for Import errors and install the required packages.
5382
"""
5383
dlg = wx.MessageDialog(None, _msg, "Warning from Plugins", wx.OK | wx.ICON_WARNING)
5384
dlg.ShowModal()
5385
dlg.Destroy()
5386
5387
app.MainLoop()
5388
5389