Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_wx/test_glcanvas.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file test_glcanvas.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
'''
20
@author: Stou Sandalski ([email protected])
21
@license: Public Domain
22
'''
23
24
# Uncomment if you have multiple wxWidgets versions
25
#import wxversion
26
# wxversion.select('2.8')
27
28
import wxmisc
29
import objpanel
30
from wxmisc import *
31
import classman as cm
32
import math
33
import wx
34
35
from wx import glcanvas
36
from wx.lib.buttons import GenBitmapTextButton, GenBitmapButton
37
try:
38
from OpenGL.GL import *
39
from OpenGL.GLU import *
40
from OpenGL.GLUT import *
41
from OpenGL.raw.GL.ARB.vertex_array_object import glGenVertexArrays, \
42
glBindVertexArray
43
44
from OpenGL.arrays import vbo
45
import numpy as np
46
47
except ImportError:
48
raise ImportError, "Required dependency OpenGL not present"
49
50
import sys
51
import os
52
import types
53
APPDIR = os.path.join(os.path.dirname(__file__), "..")
54
sys.path.append(os.path.join(APPDIR, "lib_base"))
55
IMAGEDIR = os.path.join(os.path.dirname(__file__), "images")
56
57
# wx gui stuff
58
59
60
stockIDs = [
61
wx.ID_ABOUT,
62
wx.ID_ADD,
63
wx.ID_APPLY,
64
wx.ID_BOLD,
65
wx.ID_CANCEL,
66
wx.ID_CLEAR,
67
wx.ID_CLOSE,
68
wx.ID_COPY,
69
wx.ID_CUT,
70
wx.ID_DELETE,
71
wx.ID_EDIT,
72
wx.ID_FIND,
73
wx.ID_FILE,
74
wx.ID_REPLACE,
75
wx.ID_BACKWARD,
76
wx.ID_DOWN,
77
wx.ID_FORWARD,
78
wx.ID_UP,
79
wx.ID_HELP,
80
wx.ID_HOME,
81
wx.ID_INDENT,
82
wx.ID_INDEX,
83
wx.ID_ITALIC,
84
wx.ID_JUSTIFY_CENTER,
85
wx.ID_JUSTIFY_FILL,
86
wx.ID_JUSTIFY_LEFT,
87
wx.ID_JUSTIFY_RIGHT,
88
wx.ID_NEW,
89
wx.ID_NO,
90
wx.ID_OK,
91
wx.ID_OPEN,
92
wx.ID_PASTE,
93
wx.ID_PREFERENCES,
94
wx.ID_PRINT,
95
wx.ID_PREVIEW,
96
wx.ID_PROPERTIES,
97
wx.ID_EXIT,
98
wx.ID_REDO,
99
wx.ID_REFRESH,
100
wx.ID_REMOVE,
101
wx.ID_REVERT_TO_SAVED,
102
wx.ID_SAVE,
103
wx.ID_SAVEAS,
104
wx.ID_SELECTALL,
105
wx.ID_STOP,
106
wx.ID_UNDELETE,
107
wx.ID_UNDERLINE,
108
wx.ID_UNDO,
109
wx.ID_UNINDENT,
110
wx.ID_YES,
111
wx.ID_ZOOM_100,
112
wx.ID_ZOOM_FIT,
113
wx.ID_ZOOM_IN,
114
wx.ID_ZOOM_OUT,
115
116
]
117
118
119
class BaseTool(cm.BaseObjman):
120
"""
121
This is a base tool class for Agilecanvas.
122
It must handle all mouse or keyboard events,
123
must create and draw helplines and finally
124
modify the state of client which are graphically
125
represented on the canvas.
126
"""
127
128
def __init__(self, parent, mainframe=None):
129
"""
130
To be overridden by specific tool.
131
"""
132
self.init_common('select', parent, 'Selection tool', mainframe, info='Select objects in canvas')
133
134
def set_button_info(self, bsize=(32, 32)):
135
# print 'set_button_info select tool'
136
self._bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'selectIcon.bmp'), wx.BITMAP_TYPE_BMP)
137
self._bitmap_sel = wx.Bitmap(os.path.join(IMAGEDIR, 'selectIconSel.bmp'), wx.BITMAP_TYPE_BMP)
138
139
def get_button(self, parent, bottonsize=(32, 32), bottonborder=10):
140
141
# simple stockbuttons
142
#b=wx.Button(parent, wx.ID_DELETE)
143
144
id = wx.NewId()
145
bitmap = self._bitmap
146
147
#b=GenBitmapTextToggleButton(parent, id, bitmap,tool.name,name = self.get_name())
148
b = GenBitmapToggleButton(parent, id, bitmap, (bitmap.GetWidth()+bottonborder,
149
bitmap.GetHeight()+bottonborder), name=self.get_name())
150
#b=GenBitmapToggleButton(self, wx.ID_DELETE)
151
#b = GenBitmapTextToggleButton(self, id, None, tool.get('name',''), size = (200, 45))
152
153
if bitmap is not None:
154
#mask = wx.Mask(bitmap, wx.BLUE)
155
# bitmap.SetMask(mask)
156
b.SetBitmapLabel(bitmap)
157
# bmp=wx.NullBitmap
158
159
bitmap_sel = self._bitmap_sel
160
if bitmap_sel is not None:
161
#mask = wx.Mask(bmp, wx.BLUE)
162
# bmp.SetMask(mask)
163
b.SetBitmapSelected(bitmap_sel)
164
165
b.SetUseFocusIndicator(False)
166
167
b.SetUseFocusIndicator(False)
168
# b.SetSize((36,140))
169
# b.SetBestSize()
170
tt = wx.ToolTip(self.get_info())
171
b.SetToolTip(tt) # .SetTip(tool.tooltip)
172
return b
173
174
def init_common(self, ident, parent, name, mainframe=None, info=None):
175
# print 'Agiletool.__init__',ident,name
176
self.name = name
177
self.metacanvas = None
178
# FSMnamed.__init__(self,ident,parent,name)
179
self._init_objman(ident, parent=parent, name=name.title(), info=info)
180
attrsman = self.set_attrsman(cm.Attrsman(self))
181
182
self.access = attrsman.add(cm.AttrConf('access', ['bus', 'bike', 'tram'],
183
groupnames=['options'],
184
perm='rw',
185
is_save=True,
186
name='Access list',
187
info='List with vehicle classes that have access',
188
))
189
190
self.emissiontype = attrsman.add(cm.AttrConf('emissiontype', 'Euro 0',
191
groupnames=['options'],
192
perm='rw',
193
is_save=True,
194
name='Emission type',
195
info='Emission type of vehicle',
196
))
197
# dictionary of drawobjects that will be created during
198
# the application of the tool.
199
# ident is the number in chronological order of creation,
200
# starting with one. Value is the ad hoc instance of a drawing
201
# object.
202
self.drawobjs = {}
203
self.helpobjs = {}
204
205
self.mainframe = mainframe
206
# print ' call set_button',self.ident
207
self.set_button_info()
208
self.targetsets = {}
209
# self.optionspanel=None
210
211
def append_drawobj(self, drawobj):
212
"""
213
Append new drawobject
214
"""
215
n = len(self.drawobjs)+1
216
self.drawobjs[n] = drawobj
217
218
def pop_drawobj(self):
219
"""
220
Returns most recent drawobject, removing it from the list.
221
If there are no more drwobjects in the list None is returned.
222
"""
223
224
n = len(self.drawobjs)
225
if n > 0:
226
drawobj = self.drawobjs[n]
227
del self.drawobjs[n]
228
return drawobj
229
else:
230
return None
231
232
def get_last_drawobj(self):
233
"""
234
Returns most recent drawobject, without changing the list.
235
If there are no more drwobjects in the list None is returned.
236
"""
237
n = len(self.drawobjs)
238
if n > 0:
239
drawobj = self.drawobjs[n]
240
return drawobj
241
else:
242
return None
243
244
def clear_drawobjs(self):
245
"""
246
Clear list of drawobjects, while maintaining them on metacanvas.
247
"""
248
self.drawobjs = {}
249
250
def del_drawobjs(self):
251
"""
252
Remove all drawobjects from metacanvas.
253
"""
254
while len(self.drawobjs) > 0:
255
drawobj = self.pop_drawobj()
256
self.metacanvas.del_obj(drawobj)
257
258
def make_targetsets(self, setnames=None, layer=None):
259
"""
260
Returns a dictionary with instances of targetsets as values
261
and setnames as key.
262
This allows the tool to select a list of sets from the a specific
263
layer to which it can directly communicate.
264
265
If no setnames are given then all sets of the specific layer
266
are returned.
267
268
Can be used for example to change handle settings
269
"""
270
if setnames is not None:
271
objsets = {}
272
for name in setnames:
273
objsets[name] = self.metacanvas.get_objset_from_layer(layer, name)
274
self.targetsets = objsets
275
else:
276
self.targetsets = self.metacanvas.get_objset_from_layer(layer)
277
278
def set_handles(self):
279
"""
280
Set handles to selected object sets which can be connected.
281
"""
282
# put handles on all section objects
283
for name_set in self.targetsets.keys():
284
self.metacanvas.set_handles(name_set=name_set)
285
286
def get_bitmap_from_file(self, name_bitmap):
287
# print 'get_bitmap_from_file :'+"gui/bitmaps/" + name_bitmap + ".bmp"
288
return wx.Bitmap("gui/bitmaps/" + name_bitmap + ".bmp",
289
wx.BITMAP_TYPE_BMP)
290
291
# def make_optionpanel(self,panel):
292
293
def get_optionpanel(self, parent):
294
"""
295
Return tool option widgets on given parent
296
"""
297
# print 'get_optionpanel',self
298
#button = wx.Button(parent, wx.NewId(), self.name+' Options')
299
#button.Bind(wx.EVT_BUTTON, self.set_options)
300
# return button
301
302
self.optionspanel = ObjPanel(parent, self, groups=['options'],
303
standartbuttons=[],
304
immediate_apply=True,
305
panelstyle='instrumental')
306
return self.optionspanel
307
308
def set_options(self, event):
309
"""
310
Called from options panel.
311
"""
312
print 'set_options', self.ident
313
print ' event=', event
314
pass
315
316
def set_statusbar(self, key, info):
317
pass
318
319
def activate_metacanvas(self, metacanvas):
320
"""
321
This call by metacanvas signals that the tool has been
322
activated and can now interact with metacanvas.
323
"""
324
# print 'activate_metacanvas',self.ident
325
self.metacanvas = metacanvas
326
self.metacanvas.del_handles()
327
self.activate()
328
329
def get_metacanvas(self):
330
return self.metacanvas
331
332
# def get_pentable(self):
333
# if self.metacanvas:
334
# return self.metacanvas.get_pentable()
335
336
def deactivate_metacanvas(self):
337
"""
338
This call by metacanvas signals that the tool has been
339
deactivated and can now interact with metacanvas.
340
"""
341
342
self.deactivate()
343
self.optionspanel = None
344
self.metacanvas = None
345
346
347
class DelTool(BaseTool):
348
def __init__(self, parent, mainframe=None):
349
"""
350
To be overridden by specific tool.
351
"""
352
self.init_common('delete', parent, 'Delete', mainframe, info='Delete objects in canvas')
353
354
def set_button_info(self, bsize=(32, 32)):
355
# print 'set_button_info select tool'
356
self._bitmap = None
357
self._bitmap_sel = None
358
359
def get_button(self, parent, bottonsize=(32, 32), bottonborder=10):
360
361
# simple stockbuttons
362
b = wx.Button(parent, wx.ID_DELETE, name=self.get_name())
363
364
b.SetSize(bottonsize)
365
# b.SetBestSize()
366
tt = wx.ToolTip(self.get_info())
367
b.SetToolTip(tt) # .SetTip(tool.tooltip)
368
# print 'DelTool.get_button',dir(b)
369
return b
370
371
372
class ToolPalett(wx.Panel):
373
"""
374
This is a panel where tools are represented by images and/or text.
375
The tools are selected in a radio-button-fashion.
376
377
Each tool has a string as key. Each time the status changes,
378
a callback function is called with new and old tool key as argument.
379
"""
380
381
def __init__(self, parent, tools=[], callback=None, n_buttoncolumns=4):
382
"""
383
callback is a function that is called when a tool has been selected.
384
The function is called as:
385
callback(tool)
386
387
"""
388
# the metacanvas object with which the pallet should apply th tools
389
self._callback = callback
390
391
# wx.Window.__init__(self,parent,wx.ID_ANY,wx.DefaultPosition,wx.DefaultSize,wx.SUNKEN_BORDER|wx.WANTS_CHARS)
392
# wx.Panel.__init__(self,parent,wx.ID_ANY,wx.DefaultPosition,size,wx.RAISED_BORDER|wx.WANTS_CHARS)
393
wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.DefaultSize)
394
# wx.Panel.__init__(self,parent,wx.ID_ANY,wx.DefaultPosition,(300,600),wx.RAISED_BORDER|wx.WANTS_CHARS)
395
self.sizer = wx.GridSizer(0, n_buttoncolumns, 5, 5)
396
self.SetSizer(self.sizer)
397
self._id_to_tool = {}
398
self._id = -1
399
400
for tool in tools:
401
self.add_tool(tool)
402
403
self.sizer.Fit(self)
404
# self.SetMaxSize((300,300))
405
406
def add_tool(self, tool):
407
"""
408
Add a tool to the pallet.
409
"""
410
bottonsize = (32, 32)
411
bottonborder = 10
412
toolbarborder = 1
413
414
if tool is None:
415
self.sizer.Add()
416
return None
417
else:
418
b = tool.get_button(self, bottonsize=bottonsize, bottonborder=bottonborder)
419
self.Bind(wx.EVT_BUTTON, self.on_select, b)
420
421
self._id_to_tool[b.GetId()] = (tool, b)
422
423
#self.sizer.Add(b, 0, wx.GROW)
424
self.sizer.Add(b, 0, wx.EXPAND, border=toolbarborder)
425
# self.sizer.Add(b)
426
427
return id
428
429
def add_tool_old(self, tool):
430
"""
431
Add a tool to the pallet.
432
"""
433
bottonsize = (32, 32)
434
bottonborder = 10
435
toolbarborder = 1
436
437
if tool is None:
438
self.sizer.Add()
439
return None
440
else:
441
id = wx.NewId()
442
bitmap = tool.get_buttonbitmap()
443
444
# print '\n add_tool',key,bitmap
445
# print 'toolpallet.add_tool: key,name:',tool.key,tool.name
446
#b=GenBitmapTextToggleButton(self, id, bitmap,tool.name,name = tool.name)
447
b = GenBitmapToggleButton(self, id, bitmap, (bitmap.GetWidth() +
448
bottonborder, bitmap.GetHeight()+bottonborder))
449
#b=GenBitmapToggleButton(self, wx.ID_DELETE)
450
#b = GenBitmapTextToggleButton(self, id, None, tool.get('name',''), size = (200, 45))
451
self.Bind(wx.EVT_BUTTON, self.on_select, b)
452
453
if bitmap:
454
#mask = wx.Mask(bitmap, wx.BLUE)
455
# bitmap.SetMask(mask)
456
b.SetBitmapLabel(bitmap)
457
# bmp=wx.NullBitmap
458
459
bitmap_sel = tool.get_buttonbitmap_sel()
460
if bitmap_sel:
461
#mask = wx.Mask(bmp, wx.BLUE)
462
# bmp.SetMask(mask)
463
b.SetBitmapSelected(bitmap_sel)
464
465
b.SetUseFocusIndicator(False)
466
# b.SetSize((36,140))
467
# b.SetBestSize()
468
tt = wx.ToolTip(tool.get_info())
469
b.SetToolTip(tt) # .SetTip(tool.tooltip)
470
471
self._id_to_tool[id] = (tool, b)
472
473
#self.sizer.Add(b, 0, wx.GROW)
474
475
self.sizer.Add(b, 0, wx.EXPAND, border=toolbarborder)
476
# self.sizer.Add(b)
477
478
return id
479
480
def get_tools(self):
481
"""
482
Returns lins with all toll instances
483
"""
484
tools = []
485
for (tool, b) in self._id_to_tool.values():
486
tools.append(tool)
487
return tools
488
489
def refresh(self):
490
"""
491
Reorganizes toolpallet after adding/removing tools.
492
Attention is not automatically called.
493
"""
494
self.sizer.Layout()
495
496
def on_select(self, event):
497
498
_id = event.GetEventObject().GetId()
499
print '\n on_select', _id, self._id # ,self._id_to_tool[_id]
500
if _id != self._id:
501
if self._id_to_tool.has_key(_id):
502
503
(tool, button) = self._id_to_tool[_id]
504
print ' new tool', tool.get_name()
505
self.unselect()
506
self._id = _id
507
self.GetParent().set_options(tool)
508
if self._callback is not None:
509
self._callback(tool)
510
511
def unselect(self):
512
"""
513
Unselect currently selected tool.
514
"""
515
if self._id_to_tool.has_key(self._id):
516
(tool, button) = self._id_to_tool[self._id]
517
if hasattr(button, 'SetToggle'):
518
button.SetToggle(False)
519
else:
520
# button.SetFocus()
521
# print 'button.SetFocus',button.SetFocus.__doc__
522
pass
523
524
def select(self, id):
525
"""
526
Select explicitelt a tool.
527
"""
528
print '\n select', id, self._id, self._id_to_tool
529
530
if id != self._id:
531
if self._id_to_tool.has_key(id):
532
# unselect previous
533
self.unselect()
534
535
# select and activate new tool
536
(tool, button) = self._id_to_tool[id]
537
button.SetToggle(True)
538
self._id = id
539
if self._callback is not None:
540
self._callback(tool)
541
542
543
class __ToggleMixin:
544
def SetToggle(self, flag):
545
self.up = not flag
546
self.Refresh()
547
SetValue = SetToggle
548
549
def GetToggle(self):
550
return not self.up
551
GetValue = GetToggle
552
553
def OnLeftDown(self, event):
554
if not self.IsEnabled():
555
return
556
self.saveUp = self.up
557
self.up = False # not self.up
558
self.CaptureMouse()
559
self.SetFocus()
560
self.Refresh()
561
562
def OnLeftUp(self, event):
563
if not self.IsEnabled() or not self.HasCapture():
564
return
565
if self.HasCapture():
566
if self.up != self.saveUp:
567
self.Notify()
568
self.ReleaseMouse()
569
self.Refresh()
570
571
def OnKeyDown(self, event):
572
event.Skip()
573
574
575
class GenBitmapTextToggleButton(__ToggleMixin, GenBitmapTextButton):
576
"""A generic toggle bitmap button with text label"""
577
pass
578
579
580
class GenBitmapToggleButton(__ToggleMixin, GenBitmapButton):
581
"""A generic toggle bitmap button with text label"""
582
pass
583
584
585
class ToolsPanel(wx.Panel):
586
"""
587
588
Interactively navigates through objects and displays attributes
589
on a panel.
590
"""
591
592
def __init__(self, parent):
593
wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.DefaultSize)
594
595
sizer = wx.BoxSizer(wx.VERTICAL)
596
597
self._toolspalett = ToolPalett(self)
598
599
# self._toolspalett.add_tool(BaseTool(self))
600
601
# create initial option panel
602
self._optionspanel = wx.Window(self)
603
self._optionspanel.SetBackgroundColour("pink")
604
wx.StaticText(self._optionspanel, -1, "Tool Options", (300, -1))
605
606
sizer.Add(self._toolspalett, 0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4)
607
sizer.Add(self._optionspanel, 1, wx.GROW)
608
609
# finish panel setup
610
self.SetSizer(sizer)
611
sizer.Fit(self)
612
613
# self.SetSize(parent.GetSize())
614
615
def add_tool(self, tool):
616
self._toolspalett.add_tool(tool)
617
618
def set_options(self, tool):
619
#self._optionspanel.change_obj(tool,groupnames = ['options'])
620
# self._optionspanel.change_obj(tool)
621
sizer = self.GetSizer()
622
sizer.Remove(1)
623
self._optionspanel.Destroy()
624
625
self._optionspanel = objpanel.ObjPanel(self, obj=tool,
626
attrconfigs=None,
627
#tables = None,
628
# table = None, id=None, ids=None,
629
groupnames=None,
630
func_change_obj=None,
631
show_groupnames=False, show_title=True, is_modal=False,
632
mainframe=None,
633
pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
634
immediate_apply=False, panelstyle='default',
635
standartbuttons=['apply', 'restore'])
636
# if id is not None:
637
# self.objpanel=ObjPanel(self,obj,id=id,func_change_obj=self.change_obj)
638
# else:
639
# self.objpanel=ObjPanel(self,obj,func_change_obj=self.change_obj)
640
sizer.Add(self._optionspanel, 1, wx.GROW)
641
642
self.Refresh()
643
# sizer.Fit(self)
644
sizer.Layout()
645
646
647
def get_dist_point_to_segs(p, y1, x1, y2, x2, is_ending=True):
648
"""
649
Minimum Distance between a Point p = (x,y) and a Line segments ,
650
where vectors x1, y1 are the first points and x2,y2 are the second points
651
of the line segments.
652
Written by Paul Bourke, October 1988
653
http://astronomy.swin.edu.au/~pbourke/geometry/pointline/
654
655
Rewritten in vectorial form by Joerg Schweizer
656
"""
657
658
y3, x3 = p
659
660
d = np.zeros(len(y1), dtype=np.float32)
661
662
dx21 = (x2-x1)
663
dy21 = (y2-y1)
664
665
lensq21 = dx21*dx21 + dy21*dy21
666
667
# indexvector for all zero length lines
668
iz = (lensq21 == 0)
669
670
dy = y3-y1[iz]
671
dx = x3-x1[iz]
672
673
d[iz] = dx*dx + dy*dy
674
675
lensq21[iz] = 1.0 # replace zeros with 1.0 to avoid div by zero error
676
677
u = (x3-x1)*dx21 + (y3-y1)*dy21
678
u = u / lensq21
679
680
x = x1 + u * dx21
681
y = y1 + u * dy21
682
683
if is_ending:
684
ie = u < 0
685
x[ie] = x1[ie]
686
y[ie] = y1[ie]
687
ie = u > 1
688
x[ie] = x2[ie]
689
y[ie] = y2[ie]
690
691
dx30 = x3-x
692
dy30 = y3-y
693
d[~iz] = (dx30*dx30 + dy30*dy30)[~iz]
694
return d
695
696
697
def is_inside_triangles(p, x1, y1, x2, y2, x3, y3):
698
"""
699
Returns a binary vector with True if point p is
700
inside a triangle.
701
x1,y1,x2,y2,x3,y3 are vectors with the 3 coordiantes of the triangles.
702
"""
703
alpha = ((y2 - y3)*(p[0] - x3) + (x3 - x2)*(p[1] - y3)) \
704
/ ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
705
706
beta = ((y3 - y1)*(p[0] - x3) + (x1 - x3)*(p[1] - y3)) \
707
/ ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3))
708
709
gamma = 1.0 - alpha - beta
710
return (alpha > 0) & (beta > 0) & (gamma > 0)
711
712
713
class WxGLTest_orig(glcanvas.GLCanvas):
714
def __init__(self, parent):
715
716
glcanvas.GLCanvas.__init__(self, parent, -1, attribList=[glcanvas.WX_GL_DOUBLEBUFFER])
717
wx.EVT_PAINT(self, self.OnDraw)
718
wx.EVT_SIZE(self, self.OnSize)
719
wx.EVT_MOTION(self, self.OnMouseMotion)
720
wx.EVT_WINDOW_DESTROY(self, self.OnDestroy)
721
722
self.init = True
723
724
def OnDraw(self, event):
725
self.SetCurrent()
726
727
if not self.init:
728
self.InitGL()
729
self.init = False
730
731
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
732
glLoadIdentity()
733
734
# Draw the spiral in 'immediate mode'
735
# WARNING: You should not be doing the spiral calculation inside the loop
736
# even if you are using glBegin/glEnd, sin/cos are fairly expensive functions
737
# I've left it here as is to make the code simpler.
738
radius = 1.0
739
x = radius*math.sin(0)
740
y = radius*math.cos(0)
741
glColor(0.0, 1.0, 0.0)
742
glBegin(GL_LINE_STRIP)
743
for deg in xrange(1000):
744
glVertex(x, y, 0.0)
745
rad = math.radians(deg)
746
radius -= 0.001
747
x = radius*math.sin(rad)
748
y = radius*math.cos(rad)
749
glEnd()
750
751
glEnableClientState(GL_VERTEX_ARRAY)
752
753
spiral_array = []
754
755
# Second Spiral using "array immediate mode" (i.e. Vertex Arrays)
756
radius = 0.8
757
x = radius*math.sin(0)
758
y = radius*math.cos(0)
759
glColor(1.0, 0.0, 0.0)
760
for deg in xrange(820):
761
spiral_array.append([x, y])
762
rad = math.radians(deg)
763
radius -= 0.001
764
x = radius*math.sin(rad)
765
y = radius*math.cos(rad)
766
767
glVertexPointerf(spiral_array)
768
glDrawArrays(GL_LINE_STRIP, 0, len(spiral_array))
769
glFlush()
770
self.SwapBuffers()
771
return
772
773
def InitGL(self):
774
'''
775
Initialize GL
776
'''
777
778
# # set viewing projection
779
# glClearColor(0.0, 0.0, 0.0, 1.0)
780
# glClearDepth(1.0)
781
#
782
# glMatrixMode(GL_PROJECTION)
783
# glLoadIdentity()
784
# gluPerspective(40.0, 1.0, 1.0, 30.0)
785
#
786
# glMatrixMode(GL_MODELVIEW)
787
# glLoadIdentity()
788
# gluLookAt(0.0, 0.0, 10.0,
789
# 0.0, 0.0, 0.0,
790
# 0.0, 1.0, 0.0)
791
792
def OnSize(self, event):
793
794
try:
795
width, height = event.GetSize()
796
except:
797
width = event.GetSize().width
798
height = event.GetSize().height
799
800
self.Refresh()
801
self.Update()
802
803
def OnMouseMotion(self, event):
804
x = event.GetX()
805
y = event.GetY()
806
807
def OnDestroy(self, event):
808
print "Destroying Window"
809
810
811
class Lines:
812
"""Lines class."""
813
814
def __init__(self, linewidth=3, vertices=None, colors=None):
815
self.name = 'Lines'
816
self.n_vert_per_elem = 2
817
self.linewidth = linewidth
818
self.c_highl = 0.3
819
self.detectwidth = 0.1 # m
820
self.set_attrs(vertices, colors)
821
822
def set_attrs(self, vertices, colors):
823
824
self.vertices = np.array(vertices, dtype=np.float32)
825
self._update_vertexvbo()
826
827
self.colors = np.array(colors, dtype=np.float32)
828
self.colors_highl = np.zeros((len(colors), 4), dtype=np.float32)
829
self._update_colorvbo()
830
831
def _update_vertexvbo(self):
832
self._vertexvbo = vbo.VBO(self.vertices.reshape((-1, 3)))
833
self._indexvbo = vbo.VBO(np.arange(self.n_vert_per_elem*len(self.vertices),
834
dtype=np.int32), target=GL_ELEMENT_ARRAY_BUFFER)
835
836
def _update_colorvbo(self):
837
#self._colorvbo = vbo.VBO( np.resize( np.repeat(np.clip((self.colors+self.c_highl*self.colors_highl) ,0.0,1.0), self.n_vert_per_elem),(len(self.colors),4)) )
838
self._colorvbo = vbo.VBO(np.clip((self.colors+self.colors_highl)
839
[np.array(np.arange(0, len(self.colors), 1.0/self.n_vert_per_elem), int)], 0.0, 1.0))
840
841
def pick(self, p):
842
"""
843
Returns a binary vector which is True values for lines that have been selected
844
by point p.
845
846
In particular, an element of this vector is True if the minimum distance
847
between the respective line to point p is less than self.detectwidth
848
"""
849
x1 = self.vertices[:, 0, 0]
850
y1 = self.vertices[:, 0, 1]
851
852
x2 = self.vertices[:, 1, 0]
853
y2 = self.vertices[:, 1, 1]
854
855
return get_dist_point_to_segs(p, x1, y1, x2, y2, is_ending=True) < self.detectwidth**2
856
857
def highlight(self, inds_highl):
858
self.colors_highl = np.repeat(self.c_highl*np.array(inds_highl, dtype=np.float32), 4).reshape(-1, 4)
859
self._update_colorvbo()
860
861
def draw(self):
862
glLineWidth(self.linewidth)
863
864
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
865
glEnable(GL_BLEND)
866
867
glEnableClientState(GL_VERTEX_ARRAY)
868
glEnableClientState(GL_COLOR_ARRAY)
869
870
self._colorvbo.bind()
871
glColorPointer(4, GL_FLOAT, 0, None)
872
873
self._vertexvbo.bind()
874
self._indexvbo.bind()
875
glVertexPointer(3, GL_FLOAT, 0, None)
876
877
glDrawElements(GL_LINES, self.n_vert_per_elem*len(self.vertices), GL_UNSIGNED_INT, None)
878
879
glDisableClientState(GL_VERTEX_ARRAY)
880
glDisableClientState(GL_COLOR_ARRAY)
881
self._vertexvbo.unbind()
882
self._indexvbo.unbind()
883
self._colorvbo.unbind()
884
885
886
class Rectangles(Lines):
887
888
def __init__(self, linewidth=3, vertices=None, colors=None):
889
self.name = 'Rectangles'
890
self.n_vert_per_elem = 4
891
self.c_highl = 0.3
892
self.detectwidth = 0.1 # m
893
self.linewidth = linewidth
894
895
self.set_attrs(vertices, colors)
896
897
def pick(self, p):
898
899
x1 = self.vertices[:, 0, 0]
900
y1 = self.vertices[:, 0, 1]
901
902
x2 = self.vertices[:, 1, 0]
903
y2 = self.vertices[:, 1, 1]
904
905
x3 = self.vertices[:, 2, 0]
906
y3 = self.vertices[:, 2, 1]
907
908
x4 = self.vertices[:, 3, 0]
909
y4 = self.vertices[:, 3, 1]
910
911
return is_inside_triangles(p, x1, y1, x2, y2, x3, y3) | is_inside_triangles(p, x1, y1, x3, y3, x4, y4)
912
913
def draw(self):
914
glLineWidth(self.linewidth)
915
916
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
917
glEnable(GL_BLEND)
918
919
glEnableClientState(GL_VERTEX_ARRAY)
920
glEnableClientState(GL_COLOR_ARRAY)
921
922
self._colorvbo.bind()
923
glColorPointer(4, GL_FLOAT, 0, None)
924
925
self._vertexvbo.bind()
926
self._indexvbo.bind()
927
glVertexPointer(3, GL_FLOAT, 0, None)
928
929
glDrawElements(GL_QUADS, self.n_vert_per_elem*len(self.vertices), GL_UNSIGNED_INT, None)
930
931
glDisableClientState(GL_VERTEX_ARRAY)
932
glDisableClientState(GL_COLOR_ARRAY)
933
self._vertexvbo.unbind()
934
self._indexvbo.unbind()
935
self._colorvbo.unbind()
936
937
938
class Triangles(Lines):
939
"""Triangles class."""
940
941
def __init__(self, linewidth=3, vertices=None, colors=None):
942
self.name = 'Triangles' # ,self.__name__
943
self.n_vert_per_elem = 3
944
self.c_highl = 0.3
945
self.detectwidth = 0.1 # m
946
self.linewidth = linewidth
947
948
self.set_attrs(vertices, colors)
949
950
def pick(self, p):
951
return is_inside_triangles(p, self.vertices[:, 0, 0], self.vertices[:, 0, 1], self.vertices[:, 1, 0], self.vertices[:, 1, 1], self.vertices[:, 2, 0], self.vertices[:, 2, 1])
952
953
def draw(self):
954
glLineWidth(self.linewidth)
955
956
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
957
glEnable(GL_BLEND)
958
959
glEnableClientState(GL_VERTEX_ARRAY)
960
glEnableClientState(GL_COLOR_ARRAY)
961
962
self._colorvbo.bind()
963
glColorPointer(4, GL_FLOAT, 0, None)
964
965
self._vertexvbo.bind()
966
self._indexvbo.bind()
967
glVertexPointer(3, GL_FLOAT, 0, None)
968
969
glDrawElements(GL_TRIANGLES, self.n_vert_per_elem*len(self.vertices), GL_UNSIGNED_INT, None)
970
971
glDisableClientState(GL_VERTEX_ARRAY)
972
glDisableClientState(GL_COLOR_ARRAY)
973
self._vertexvbo.unbind()
974
self._indexvbo.unbind()
975
self._colorvbo.unbind()
976
977
978
class GLFrame(wx.Frame):
979
"""A simple class for using OpenGL with wxPython."""
980
981
def __init__(self, parent, id=-1, title='', pos=wx.DefaultPosition,
982
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
983
name='frame', mainframe=None):
984
985
print '\n\nGLFrame!!'
986
if mainframe is None:
987
self._mainframe = parent
988
else:
989
self._mainframe = mainframe
990
991
self._elements = []
992
self.elements_selected = []
993
994
self.eyex = 0.0
995
self.eyey = 0.0
996
self.eyez = -9.0
997
998
self.centerx = 0.0
999
self.centery = 0.0
1000
self.centerz = 0.0
1001
1002
self.upx = -1.0
1003
self.upy = 0.0
1004
self.upz = 0.0
1005
1006
self.g_Width = 600
1007
self.g_Height = 600
1008
1009
self.g_nearPlane = 1.
1010
self.g_farPlane = 1000.
1011
1012
self.action = ""
1013
self.xStart = self.yStart = 0.
1014
self.xStart
1015
self.zoom = 65.
1016
1017
self.xRotate = 0.
1018
self.yRotate = 0.
1019
self.zRotate = 0.
1020
1021
self.xTrans = 0.
1022
self.yTrans = 0.
1023
1024
#
1025
# Forcing a specific style on the window.
1026
# Should this include styles passed?
1027
style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
1028
1029
super(GLFrame, self).__init__(parent, id, title, pos, size, style, name)
1030
#wx.Frame.__init__(self, parent, id, title, pos, size, style, name)
1031
1032
self.GLinitialized = False
1033
attribList = (glcanvas.WX_GL_RGBA, # RGBA
1034
glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered
1035
glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit
1036
1037
#
1038
# Create the canvas
1039
self.canvas = glcanvas.GLCanvas(self, attribList=attribList)
1040
1041
#
1042
# Set the event handlers.
1043
self.canvas.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent)
1044
self.canvas.Bind(wx.EVT_SIZE, self.processSizeEvent)
1045
self.canvas.Bind(wx.EVT_PAINT, self.processPaintEvent)
1046
1047
self.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
1048
self.canvas.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
1049
self.canvas.Bind(wx.EVT_MOTION, self.OnMotion)
1050
self.canvas.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
1051
1052
self.Show()
1053
# this is needed to initialize GL projections for unproject
1054
wx.CallAfter(self.processSizeEvent)
1055
1056
def add_element(self, element):
1057
self._elements.append(element)
1058
self.OnDraw()
1059
1060
def resetView():
1061
self.zoom = 65.
1062
self.xRotate = 0.
1063
self.yRotate = 0.
1064
self.zRotate = 0.
1065
self.xTrans = 0.
1066
self.yTrans = 0.
1067
self.OnDraw()
1068
1069
def OnWheel(self, event):
1070
#EventType = FloatCanvas.EVT_FC_MOUSEWHEEL
1071
#
1072
Rot = event.GetWheelRotation()
1073
# print 'OnWheel!!',Rot,event.ControlDown(),event.ShiftDown()
1074
if event.ControlDown(): # event.ControlDown(): # zoom
1075
if Rot < 0:
1076
self.zoom *= 0.9
1077
else:
1078
self.zoom *= 1.1
1079
self.OnDraw()
1080
event.Skip()
1081
1082
def OnLeftDown(self, event):
1083
##
1084
if (event.ControlDown() & event.ShiftDown()) & (self.action == ''):
1085
self.action = 'drag'
1086
self.BeginGrap(event)
1087
event.Skip()
1088
1089
def OnLeftUp(self, event):
1090
if self.action == 'drag':
1091
self.EndGrap(event)
1092
self.action == ''
1093
event.Skip()
1094
1095
def get_intersection(self, v_near, v_far):
1096
# 150918
1097
# idea from http://www.bfilipek.com/2012/06/select-mouse-opengl.html
1098
# https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection
1099
d = -v_near + v_far
1100
1101
t = -v_near[2]/d[2]
1102
v_inter = v_near+t*d
1103
1104
return v_inter
1105
1106
def OnMotion(self, event):
1107
1108
p = self.unproject(event)[0:2]
1109
for element in self._elements:
1110
inds_pick = element.pick(p)
1111
element.highlight(inds_pick)
1112
1113
self.OnDraw()
1114
1115
if (event.ControlDown() & event.ShiftDown() & (self.action == 'drag')):
1116
self.MoveGrap(event)
1117
self.OnDraw()
1118
event.Skip()
1119
1120
elif (self.action == 'drag'):
1121
self.EndGrap(event)
1122
self.action == ''
1123
event.Skip()
1124
1125
def unproject(self, event):
1126
"""Get the world coordinates for viewCoordinate for the event
1127
"""
1128
mousex, mousey = event.GetPosition()
1129
x = mousex
1130
y = self.g_Height-mousey
1131
1132
modelviewmatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
1133
projectionmatrix = glGetDoublev(GL_PROJECTION_MATRIX)
1134
viewport = glGetInteger(GL_VIEWPORT)
1135
z = 0.0
1136
worldCoordinate_near = np.array(gluUnProject(
1137
x, y, z,
1138
modelviewmatrix,
1139
projectionmatrix,
1140
viewport,), dtype=np.float32)
1141
z = 1.0
1142
worldCoordinate_far = np.array(gluUnProject(
1143
x, y, z,
1144
modelviewmatrix,
1145
projectionmatrix,
1146
viewport,), dtype=np.float32)
1147
1148
v_inter = self.get_intersection(worldCoordinate_near, worldCoordinate_far)
1149
return v_inter
1150
1151
def BeginGrap(self, event):
1152
1153
self.xStart, self.yStart = event.GetPosition()
1154
# print 'BeginGrap',self.xStart,self.yStart
1155
1156
def MoveGrap(self, event):
1157
x, y = event.GetPosition()
1158
1159
self.xTrans += x-self.xStart
1160
self.yTrans += y-self.yStart
1161
# print 'MoveGrap',self.xTrans,self.yTrans
1162
self.xStart, self.yStart = x, y
1163
1164
def EndGrap(self, event):
1165
# print 'EndGrap'
1166
self.canvas.SetCursor(wx.NullCursor)
1167
self.action = ''
1168
1169
#
1170
# Canvas Proxy Methods
1171
1172
def GetGLExtents(self):
1173
"""Get the extents of the OpenGL canvas."""
1174
return self.canvas.GetClientSize()
1175
1176
def SwapBuffers(self):
1177
"""Swap the OpenGL buffers."""
1178
self.canvas.SwapBuffers()
1179
1180
#
1181
# wxPython Window Handlers
1182
1183
def processEraseBackgroundEvent(self, event):
1184
"""Process the erase background event."""
1185
pass # Do nothing, to avoid flashing on MSWin
1186
1187
def processSizeEvent(self, event=None):
1188
"""Process the resize event."""
1189
if self.canvas.GetContext():
1190
# Make sure the frame is shown before calling SetCurrent.
1191
self.Show()
1192
self.canvas.SetCurrent()
1193
1194
size = self.GetGLExtents()
1195
self.OnReshape(size.width, size.height)
1196
self.canvas.Refresh(False)
1197
if event:
1198
event.Skip()
1199
1200
def processPaintEvent(self, event):
1201
"""Process the drawing event."""
1202
self.canvas.SetCurrent()
1203
1204
# This is a 'perfect' time to initialize OpenGL ... only if we need to
1205
if not self.GLinitialized:
1206
self.OnInitGL()
1207
self.GLinitialized = True
1208
1209
self.OnDraw()
1210
event.Skip()
1211
1212
#
1213
# GLFrame OpenGL Event Handlers
1214
1215
def OnInitGL(self):
1216
"""Initialize OpenGL for use in the window."""
1217
glClearColor(0, 0, 0, 1)
1218
1219
def OnReshape(self, width, height):
1220
"""Reshape the OpenGL viewport based on the dimensions of the window."""
1221
#global g_Width, g_Height
1222
self.g_Width = width
1223
self.g_Height = height
1224
glViewport(0, 0, self.g_Width, self.g_Height)
1225
1226
def OnDraw(self, *args, **kwargs):
1227
"""Draw the window."""
1228
# Clear frame buffer and depth buffer
1229
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
1230
# Set up viewing transformation, looking down -Z axis
1231
glLoadIdentity()
1232
gluLookAt(self.eyex, self.eyey, self.eyez, self.centerx, self.centery,
1233
self.centerz, self.upx, self.upy, self.upz) # -.1,0,0
1234
1235
# Set perspective (also zoom)
1236
glMatrixMode(GL_PROJECTION)
1237
glLoadIdentity()
1238
# the window corner OpenGL coordinates are (-+1, -+1)
1239
glOrtho(-1, 1, 1, -1, -1, 1)
1240
1241
aspect = float(self.g_Width)/float(self.g_Height)
1242
1243
gluPerspective(self.zoom, aspect, self.g_nearPlane, self.g_farPlane)
1244
glMatrixMode(GL_MODELVIEW)
1245
self.polarView()
1246
1247
# draw actual scene
1248
for element in self._elements:
1249
element.draw()
1250
1251
self.SwapBuffers()
1252
1253
def polarView(self):
1254
glTranslatef(self.yTrans/100., 0.0, 0.0)
1255
glTranslatef(0.0, -self.xTrans/100., 0.0)
1256
glRotatef(-self.zRotate, 0.0, 0.0, 1.0)
1257
glRotatef(-self.xRotate, 1.0, 0.0, 0.0)
1258
glRotatef(-self.yRotate, .0, 1.0, 0.0)
1259
1260
1261
class WxGLTest2(glcanvas.GLCanvas):
1262
def __init__(self, parent, mainframe=None):
1263
if mainframe is None:
1264
self._mainframe = parent
1265
else:
1266
self._mainframe = mainframe
1267
1268
self._elements = []
1269
self.elements_selected = []
1270
1271
self.eyex = 0.0
1272
self.eyey = 0.0
1273
self.eyez = -9.0
1274
1275
self.centerx = 0.0
1276
self.centery = 0.0
1277
self.centerz = 0.0
1278
1279
self.upx = -1.0
1280
self.upy = 0.0
1281
self.upz = 0.0
1282
1283
self.g_Width = 600
1284
self.g_Height = 600
1285
1286
self.g_nearPlane = 1.
1287
self.g_farPlane = 1000.
1288
1289
self.action = ""
1290
self.xStart = self.yStart = 0.
1291
self.xStart
1292
self.zoom = 65.
1293
1294
self.xRotate = 0.
1295
self.yRotate = 0.
1296
self.zRotate = 0.
1297
1298
self.xTrans = 0.
1299
self.yTrans = 0.
1300
1301
#
1302
# Forcing a specific style on the window.
1303
# Should this include styles passed?
1304
style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
1305
1306
attribList = (glcanvas.WX_GL_RGBA, # RGBA
1307
glcanvas.WX_GL_DOUBLEBUFFER, # Double Buffered
1308
glcanvas.WX_GL_DEPTH_SIZE, 24) # 24 bit
1309
1310
glcanvas.GLCanvas.__init__(self, parent, -1, attribList=attribList)
1311
#super(WxGLTest2, self).__init__(parent,-1, attribList=attribList)
1312
1313
self.GLinitialized = False
1314
1315
###
1316
# Forcing a specific style on the window.
1317
# Should this include styles passed?
1318
#style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
1319
1320
#super(GLFrame, self).__init__(parent, id, title, pos, size, style, name)
1321
#wx.Frame.__init__(self, parent, id, title, pos, size, style, name)
1322
1323
#
1324
# Set the event handlers.
1325
self.Bind(wx.EVT_ERASE_BACKGROUND, self.processEraseBackgroundEvent)
1326
self.Bind(wx.EVT_SIZE, self.OnSize)
1327
self.Bind(wx.EVT_PAINT, self.processPaintEvent)
1328
1329
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
1330
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
1331
self.Bind(wx.EVT_MOTION, self.OnMotion)
1332
self.Bind(wx.EVT_MOUSEWHEEL, self.OnWheel)
1333
1334
# this is needed to initialize GL projections for unproject
1335
wx.CallAfter(self.OnSize)
1336
1337
def add_element(self, element):
1338
self._elements.append(element)
1339
self.OnDraw()
1340
1341
def resetView():
1342
self.zoom = 65.
1343
self.xRotate = 0.
1344
self.yRotate = 0.
1345
self.zRotate = 0.
1346
self.xTrans = 0.
1347
self.yTrans = 0.
1348
self.OnDraw()
1349
1350
def OnWheel(self, event):
1351
#EventType = FloatCanvas.EVT_FC_MOUSEWHEEL
1352
#
1353
Rot = event.GetWheelRotation()
1354
# print 'OnWheel!!',Rot,event.ControlDown(),event.ShiftDown()
1355
if event.ControlDown(): # event.ControlDown(): # zoom
1356
if Rot < 0:
1357
self.zoom *= 0.9
1358
else:
1359
self.zoom *= 1.1
1360
self.OnDraw()
1361
event.Skip()
1362
1363
def OnLeftDown(self, event):
1364
##
1365
if (event.ControlDown() & event.ShiftDown()) & (self.action == ''):
1366
self.action = 'drag'
1367
self.BeginGrap(event)
1368
event.Skip()
1369
1370
def OnLeftUp(self, event):
1371
if self.action == 'drag':
1372
self.EndGrap(event)
1373
self.action == ''
1374
event.Skip()
1375
1376
def get_intersection(self, v_near, v_far):
1377
# 150918
1378
# idea from http://www.bfilipek.com/2012/06/select-mouse-opengl.html
1379
# https://en.wikipedia.org/wiki/Line%E2%80%93plane_intersection
1380
d = -v_near + v_far
1381
1382
t = -v_near[2]/d[2]
1383
v_inter = v_near+t*d
1384
1385
return v_inter
1386
1387
def OnMotion(self, event):
1388
1389
p = self.unproject(event)[0:2]
1390
for element in self._elements:
1391
inds_pick = element.pick(p)
1392
element.highlight(inds_pick)
1393
1394
self.OnDraw()
1395
1396
if (event.ControlDown() & event.ShiftDown() & (self.action == 'drag')):
1397
self.MoveGrap(event)
1398
self.OnDraw()
1399
event.Skip()
1400
1401
elif (self.action == 'drag'):
1402
self.EndGrap(event)
1403
self.action == ''
1404
event.Skip()
1405
1406
def unproject(self, event):
1407
"""Get the world coordinates for viewCoordinate for the event
1408
"""
1409
mousex, mousey = event.GetPosition()
1410
x = mousex
1411
y = self.g_Height-mousey
1412
1413
modelviewmatrix = glGetDoublev(GL_MODELVIEW_MATRIX)
1414
projectionmatrix = glGetDoublev(GL_PROJECTION_MATRIX)
1415
viewport = glGetInteger(GL_VIEWPORT)
1416
z = 0.0
1417
worldCoordinate_near = np.array(gluUnProject(
1418
x, y, z,
1419
modelviewmatrix,
1420
projectionmatrix,
1421
viewport,), dtype=np.float32)
1422
z = 1.0
1423
worldCoordinate_far = np.array(gluUnProject(
1424
x, y, z,
1425
modelviewmatrix,
1426
projectionmatrix,
1427
viewport,), dtype=np.float32)
1428
1429
v_inter = self.get_intersection(worldCoordinate_near, worldCoordinate_far)
1430
return v_inter
1431
1432
def BeginGrap(self, event):
1433
1434
self.xStart, self.yStart = event.GetPosition()
1435
# print 'BeginGrap',self.xStart,self.yStart
1436
1437
def MoveGrap(self, event):
1438
x, y = event.GetPosition()
1439
1440
self.xTrans += x-self.xStart
1441
self.yTrans += y-self.yStart
1442
# print 'MoveGrap',self.xTrans,self.yTrans
1443
self.xStart, self.yStart = x, y
1444
1445
def EndGrap(self, event):
1446
# print 'EndGrap'
1447
self.SetCursor(wx.NullCursor)
1448
self.action = ''
1449
1450
#
1451
# Canvas Proxy Methods
1452
1453
def GetGLExtents(self):
1454
"""Get the extents of the OpenGL canvas."""
1455
return self.GetClientSize()
1456
1457
# def SwapBuffers(self):
1458
# """Swap the OpenGL buffers."""
1459
# self.SwapBuffers()
1460
1461
#
1462
# wxPython Window Handlers
1463
1464
def processEraseBackgroundEvent(self, event):
1465
"""Process the erase background event."""
1466
pass # Do nothing, to avoid flashing on MSWin
1467
1468
def OnSize(self, event=None, win=None):
1469
"""Process the resize event."""
1470
if self.GetContext():
1471
# Make sure the frame is shown before calling SetCurrent.
1472
self.Show()
1473
self.SetCurrent()
1474
1475
size = self.GetGLExtents()
1476
self.OnReshape(size.width, size.height)
1477
self.Refresh(False)
1478
if event:
1479
event.Skip()
1480
1481
def processPaintEvent(self, event):
1482
"""Process the drawing event."""
1483
self.SetCurrent()
1484
1485
# This is a 'perfect' time to initialize OpenGL ... only if we need to
1486
if not self.GLinitialized:
1487
self.OnInitGL()
1488
self.GLinitialized = True
1489
1490
self.OnDraw()
1491
event.Skip()
1492
1493
#
1494
# GLFrame OpenGL Event Handlers
1495
1496
def OnInitGL(self):
1497
"""Initialize OpenGL for use in the window."""
1498
glClearColor(0, 0, 0, 1)
1499
1500
def OnReshape(self, width, height):
1501
"""Reshape the OpenGL viewport based on the dimensions of the window."""
1502
#global g_Width, g_Height
1503
self.g_Width = width
1504
self.g_Height = height
1505
glViewport(0, 0, self.g_Width, self.g_Height)
1506
1507
def OnDraw(self, *args, **kwargs):
1508
"""Draw the window."""
1509
# Clear frame buffer and depth buffer
1510
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
1511
# Set up viewing transformation, looking down -Z axis
1512
glLoadIdentity()
1513
gluLookAt(self.eyex, self.eyey, self.eyez, self.centerx, self.centery,
1514
self.centerz, self.upx, self.upy, self.upz) # -.1,0,0
1515
1516
# Set perspective (also zoom)
1517
glMatrixMode(GL_PROJECTION)
1518
glLoadIdentity()
1519
# the window corner OpenGL coordinates are (-+1, -+1)
1520
glOrtho(-1, 1, 1, -1, -1, 1)
1521
1522
aspect = float(self.g_Width)/float(self.g_Height)
1523
1524
gluPerspective(self.zoom, aspect, self.g_nearPlane, self.g_farPlane)
1525
glMatrixMode(GL_MODELVIEW)
1526
self.polarView()
1527
1528
# draw actual scene
1529
for element in self._elements:
1530
element.draw()
1531
# causes bad things :AttributeError: 'Implementation' object has no attribute 'glGenBuffers'
1532
1533
self.SwapBuffers()
1534
1535
def polarView(self):
1536
glTranslatef(self.yTrans/100., 0.0, 0.0)
1537
glTranslatef(0.0, -self.xTrans/100., 0.0)
1538
glRotatef(-self.zRotate, 0.0, 0.0, 1.0)
1539
glRotatef(-self.xRotate, 1.0, 0.0, 0.0)
1540
glRotatef(-self.yRotate, .0, 1.0, 0.0)
1541
1542
1543
class GlEditorSash(wx.SplitterWindow):
1544
1545
def __init__(self, parent,
1546
mainframe=None,
1547
size=wx.DefaultSize,
1548
is_menu=False, # create menu items
1549
Debug=0,
1550
):
1551
1552
wx.SplitterWindow.__init__(self, parent, wx.ID_ANY,
1553
style=wx.SP_LIVE_UPDATE,
1554
size=size)
1555
self.log = log
1556
1557
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
1558
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
1559
1560
# id=wx.ID_ANY
1561
# pixel_snap=10 # radius in pixels in which a point is selected
1562
# n_test=5
1563
# wx.Window.__init__(self,parent,id,wx.DefaultPosition,wx.DefaultSize,wx.SUNKEN_BORDER|wx.WANTS_CHARS)
1564
# wx.Panel.__init__(self,parent,id,wx.DefaultPosition,size,wx.SUNKEN_BORDER|wx.WANTS_CHARS)
1565
# self.parent=parent
1566
self._mainframe = mainframe # mainframe
1567
#splitter = Splitter(self)
1568
1569
self._toolspanel = ToolPalett(self)
1570
self._toolspanel.add_tool(BaseTool(self))
1571
#sty = wx.BORDER_SUNKEN
1572
#self._toolspanel = wx.Window(self, style=sty)
1573
# self._toolspanel.SetBackgroundColour("pink")
1574
#wx.StaticText(self._toolspanel, -1, "Object", (50,50))
1575
1576
self._canvas = WxGLTest2(self)
1577
#p2 = wx.Window(self, style=sty)
1578
# p2.SetBackgroundColour("blue")
1579
#wx.StaticText(p2, -1, "GLeditor", (50,50))
1580
1581
#self.canvas = wx.Window(splitter, style=sty)
1582
# self.canvas.SetBackgroundColour("green")
1583
#wx.StaticText(self.canvas, -1, "Panel two", (50,50))
1584
1585
#self.canvas = WxGLTest2(splitter)
1586
#self.canvas = WxGLTest_orig(splitter)
1587
1588
#nbpanel = wx.Panel(splitter)
1589
#self._viewtabs = wx.Notebook(nbpanel,wx.ID_ANY, style=wx.CLIP_CHILDREN)
1590
#sizer = wx.BoxSizer(wx.VERTICAL)
1591
#sizer.Add(self._viewtabs, 1, wx.ALL|wx.EXPAND, 5)
1592
# nbpanel.SetSizer(sizer)
1593
# self.Layout()
1594
1595
# finally, put the notebook in a sizer for the panel to manage
1596
# the layout
1597
#sizer = wx.BoxSizer()
1598
#sizer.Add(self._viewtabs, 1, wx.EXPAND)
1599
# self.SetSizer(sizer)
1600
1601
self.SetMinimumPaneSize(20)
1602
#splitter.SplitVertically(p1, self.canvas, -100)
1603
self.SplitVertically(self._toolspanel, self._canvas, -100)
1604
1605
#wx.EVT_SIZE (self, self.on_size)
1606
self.SetSashPosition(500, True)
1607
# sizer=wx.BoxSizer(wx.VERTICAL)
1608
# sizer.Add(p1,0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4)# from NaviPanelTest
1609
# sizer.Add(self.canvas,1,wx.GROW)# from NaviPanelTest
1610
1611
# finish panel setup
1612
# self.SetSizer(sizer)
1613
# sizer.Fit(self)
1614
# self.on_size()
1615
# self.Show()
1616
1617
def get_canvas(self):
1618
return self._canvas
1619
1620
def OnSashChanged(self, evt):
1621
#print("sash changed to %s\n" % str(evt.GetSashPosition()))
1622
pass
1623
1624
def OnSashChanging(self, evt):
1625
print("sash changing to %s\n" % str(evt.GetSashPosition()))
1626
# uncomment this to not allow the change
1627
# evt.SetSashPosition(-1)
1628
# evt.SetSashPosition(210)
1629
# self.canvas.OnSize()
1630
pass
1631
1632
def on_size(self, event=None):
1633
# self.tc.SetSize(self.GetSize())
1634
# self.tc.SetSize(self.GetSize())
1635
# self._viewtabs.SetSize(self.GetSize())
1636
# pass
1637
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1638
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1639
1640
# important:
1641
#wx.LayoutAlgorithm().LayoutWindow(self, self._viewtabs)
1642
1643
if event:
1644
event.Skip()
1645
1646
1647
class GlEditor(wx.Panel):
1648
1649
def __init__(self, parent,
1650
mainframe=None,
1651
size=wx.DefaultSize,
1652
is_menu=False, # create menu items
1653
Debug=0,
1654
):
1655
1656
wx.Panel.__init__(self, parent, wx.ID_ANY, size=size)
1657
sizer = wx.BoxSizer(wx.HORIZONTAL)
1658
1659
self._mainframe = mainframe
1660
1661
self._toolspanel = ToolsPanel(self)
1662
for i in range(5):
1663
self._toolspanel.add_tool(BaseTool(self))
1664
self._toolspanel.add_tool(DelTool(self))
1665
#sty = wx.BORDER_SUNKEN
1666
#self._toolspanel = wx.Window(self, style=sty)
1667
# self._toolspanel.SetBackgroundColour("pink")
1668
#wx.StaticText(self._toolspanel, -1, "Object", (50,50))
1669
1670
self._canvas = WxGLTest2(self)
1671
#p2 = wx.Window(self, style=sty)
1672
# p2.SetBackgroundColour("blue")
1673
#wx.StaticText(p2, -1, "GLeditor", (50,50))
1674
1675
sizer.Add(self._toolspanel, 0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4) # from NaviPanelTest
1676
sizer.Add(self._canvas, 1, wx.GROW) # from NaviPanelTest
1677
1678
# finish panel setup
1679
self.SetSizer(sizer)
1680
sizer.Fit(self)
1681
1682
def get_canvas(self):
1683
return self._canvas
1684
1685
def on_size(self, event=None):
1686
# self.tc.SetSize(self.GetSize())
1687
# self.tc.SetSize(self.GetSize())
1688
# self._viewtabs.SetSize(self.GetSize())
1689
# pass
1690
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1691
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1692
1693
# important:
1694
#wx.LayoutAlgorithm().LayoutWindow(self, self._viewtabs)
1695
1696
if event:
1697
event.Skip()
1698
1699
1700
class MainSplitter(wx.SplitterWindow):
1701
def __init__(self, parent, ID=-1):
1702
wx.SplitterWindow.__init__(self, parent, ID,
1703
style=wx.SP_LIVE_UPDATE
1704
)
1705
1706
self.SetMinimumPaneSize(20)
1707
1708
#sty = wx.BORDER_SUNKEN
1709
1710
emptyobj = cm.BaseObjman('empty')
1711
self._objbrowser = objpanel.NaviPanel(self,
1712
emptyobj,
1713
#show_title = False
1714
#size = w.DefaultSize,
1715
#style = wx.DEFAULT_DIALOG_STYLE|wx.MAXIMIZE_BOX|wx.RESIZE_BORDER,
1716
# choose_id=False,choose_attr=False,
1717
# func_choose_id=None,
1718
# func_change_obj=None,
1719
#panelstyle = 'default',
1720
immediate_apply=False,
1721
buttons=[],
1722
standartbuttons=[],
1723
#defaultbutton = defaultbutton,
1724
)
1725
1726
#p1 = wx.Window(splitter, style=sty)
1727
# p1.SetBackgroundColour("pink")
1728
#wx.StaticText(p1, -1, "Object", (50,50))
1729
1730
#self.canvas = wx.Window(splitter, style=sty)
1731
# self.canvas.SetBackgroundColour("green")
1732
#wx.StaticText(self.canvas, -1, "Panel two", (50,50))
1733
#self.canvas = WxGLTest2(splitter)
1734
#self.canvas = WxGLTest_orig(splitter)
1735
1736
#self._viewtabs = wx.Notebook(self,wx.ID_ANY, style=wx.CLIP_CHILDREN)
1737
self._viewtabs = wx.Notebook(self, -1, size=(21, 21), style=wx.BK_DEFAULT
1738
# wx.BK_TOP
1739
# wx.BK_BOTTOM
1740
# wx.BK_LEFT
1741
# wx.BK_RIGHT
1742
# | wx.NB_MULTILINE
1743
)
1744
1745
#nbpanel = wx.Panel(splitter)
1746
#self._viewtabs = wx.Notebook(nbpanel,wx.ID_ANY, style=wx.CLIP_CHILDREN)
1747
#sizer = wx.BoxSizer(wx.VERTICAL)
1748
#sizer.Add(self._viewtabs, 1, wx.ALL|wx.EXPAND, 5)
1749
# nbpanel.SetSizer(sizer)
1750
# self.Layout()
1751
1752
# finally, put the notebook in a sizer for the panel to manage
1753
# the layout
1754
#sizer = wx.BoxSizer()
1755
#sizer.Add(self._viewtabs, 1, wx.EXPAND)
1756
# self.SetSizer(sizer)
1757
1758
#splitter.SplitVertically(self._objbrowser,self.canvas , -100)
1759
self.SplitVertically(self._objbrowser, self._viewtabs, -100)
1760
1761
self.SetSashPosition(500, True)
1762
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)
1763
self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
1764
1765
def add_view(self, name, ViewClass, **args):
1766
"""
1767
Add a new view to the notebook.
1768
"""
1769
# print 'context.add_view',ViewClass
1770
# print ' args',args
1771
view = ViewClass(self._viewtabs,
1772
mainframe=self.GetParent(),
1773
**args
1774
)
1775
1776
# Add network tab with editor
1777
p = self._viewtabs.AddPage(view, name.title())
1778
#self._views[name] = view
1779
# self._viewtabs.SetSelection(p)
1780
# self._viewtabs.Show(True)
1781
return view
1782
1783
def OnSashChanged(self, evt):
1784
#print("sash changed to %s\n" % str(evt.GetSashPosition()))
1785
pass
1786
1787
def OnSashChanging(self, evt):
1788
#print("sash changing to %s\n" % str(evt.GetSashPosition()))
1789
# uncomment this to not allow the change
1790
# evt.SetSashPosition(-1)
1791
# self.canvas.OnSize()
1792
pass
1793
1794
1795
class TestMainframe(AgileToolbarFrameMixin, wx.Frame):
1796
"""
1797
Simple wx frame with some special features.
1798
"""
1799
1800
def __init__(self, parent=None, id=-1, title='mainframe', pos=wx.DefaultPosition,
1801
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
1802
name='frame'):
1803
1804
# Forcing a specific style on the window.
1805
# Should this include styles passed?
1806
style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE
1807
wx.Frame.__init__(self, parent, id, title, pos, size=size, style=style, name=name)
1808
#super(GLFrame, self).__init__(parent, id, title, pos, size, style, name)
1809
self._splitter = MainSplitter(self)
1810
self._views = {}
1811
#wx.EVT_SIZE (self, self.on_size)
1812
# sizer=wx.BoxSizer(wx.VERTICAL)
1813
# sizer.Add(p1,0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4)# from NaviPanelTest
1814
# sizer.Add(self.canvas,1,wx.GROW)# from NaviPanelTest
1815
1816
# finish panel setup
1817
# self.SetSizer(sizer)
1818
# sizer.Fit(self)
1819
# self.Show()
1820
1821
# this is needed to initialize GL projections for unproject
1822
# wx.CallAfter(self.on_size)
1823
1824
#width,height = self.GetSize()
1825
#self._splitter.SetSashPosition(300, True)
1826
# maximize the frame
1827
self.Maximize()
1828
# self.CenterOnScreen()
1829
#################################################################
1830
# create statusbar
1831
#self.statusbar = AgileStatusbar(self)
1832
self.statusbar = AgileStatusbar(self)
1833
self.SetStatusBar(self.statusbar)
1834
# self.count=0.0
1835
1836
#################################################################
1837
# create toolbar
1838
1839
tsize = (16, 16)
1840
self.init_toolbar(size=tsize)
1841
1842
#new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize)
1843
#open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize)
1844
#save_bmp= wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, tsize)
1845
#cut_bmp = wx.ArtProvider.GetBitmap(wx.ART_CUT, wx.ART_TOOLBAR, tsize)
1846
#copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize)
1847
#paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize)
1848
1849
#self.add_tool('new',self.on_open,new_bmp,'create new doc')
1850
#self.add_tool('open',self.on_open,open_bmp,'Open doc')
1851
#self.add_tool('save',self.on_save,save_bmp,'Save doc')
1852
# self.toolbar.AddSeparator()
1853
# self.add_tool('cut',self.on_open,cut_bmp,'Cut')
1854
# self.add_tool('copy',self.on_open,copy_bmp,'Copy')
1855
# self.add_tool('paste',self.on_open,paste_bmp,'Paste')
1856
1857
# self.SetToolBar(self.toolbar)
1858
1859
#################################################################
1860
# create the menu bar
1861
1862
self.menubar = AgileMenubar(self)
1863
self.menubar.append_menu('file')
1864
self.menubar.append_menu('file/doc')
1865
1866
self.menubar.append_item('file/doc/open', self.on_open,
1867
shortkey='Ctrl+o', info='open it out')
1868
1869
self.menubar.append_item('file/doc/save', self.on_save,
1870
shortkey='Ctrl+s', info='save it out')
1871
1872
# self.menubar.append_menu('edit')
1873
# self.menubar.append_item('edit/cut',self.cut,\
1874
# shortkey='Ctrl+c',info='cut it out')
1875
1876
# self.menubar.append_item('edit/toggle',self.toggle_tools,\
1877
# shortkey='Ctrl+t',info='toggle tools')
1878
# self.menubar.append_menu('tools')
1879
self.SetMenuBar(self.menubar)
1880
# self.Show(True) #NO!!
1881
1882
def add_view(self, name, ViewClass, **args):
1883
"""
1884
Add a new view to the notebook.
1885
"""
1886
# print 'context.add_view',ViewClass
1887
# print ' args',args
1888
1889
view = self._splitter.add_view(name, ViewClass, **args)
1890
self._views[name] = view
1891
# self._viewtabs.SetSelection(p)
1892
# self._splitter._viewtabs.Show(True)
1893
return view
1894
1895
def on_size(self, event=None):
1896
print 'Mainframe.on_size'
1897
# self.tc.SetSize(self.GetSize())
1898
# self.tc.SetSize(self.GetSize())
1899
# self._viewtabs.SetSize(self.GetSize())
1900
# pass
1901
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1902
#wx.LayoutAlgorithm().LayoutWindow(self, self.p1)
1903
1904
# important:
1905
#wx.LayoutAlgorithm().LayoutWindow(self, self._viewtabs)
1906
wx.LayoutAlgorithm().LayoutWindow(self, self._splitter)
1907
if event:
1908
event.Skip()
1909
1910
def on_save(self, event):
1911
print 'save it!!'
1912
1913
def on_open(self, event):
1914
"""Open a document"""
1915
#wildcards = CreateWildCards() + "All files (*.*)|*.*"
1916
print 'open it!!'
1917
1918
def destroy(self):
1919
"""Destroy this object"""
1920
# self.theDocManager.theDestructor()
1921
#imgPreferences.saveXml(self.GetStartDirectory() + "/" + imgINI_FILE_NAME)
1922
##del self.thePrint
1923
self.Destroy()
1924
1925
def on_close(self, event):
1926
# self.Close(True)
1927
# pass
1928
self.destroy()
1929
1930
def on_exit(self, event):
1931
"""Called when the application is to be finished"""
1932
self.destroy()
1933
1934
def on_idle(self, event):
1935
pass
1936
#self.count = self.count + 1
1937
# if self.count >= 100:
1938
# self.count = 0
1939
1940
# self.statusbar.set_progress(self.count)
1941
1942
def on_about(self, event):
1943
"""Display the information about this application"""
1944
#dlg = imgDlgAbout(self, -1, "")
1945
# dlg.ShowModal()
1946
# dlg.Destroy()
1947
pass
1948
1949
1950
linewidth = 3
1951
vertices = [
1952
[[0.0, 0.0, 0.0], [0.2, 0.0, 0.0]], # 0 green
1953
[[0.0, 0.0, 0.0], [0.0, 0.9, 0.0]], # 1 red
1954
]
1955
1956
1957
colors = [
1958
[0.0, 0.9, 0.0, 0.9], # 0
1959
[0.9, 0.0, 0.0, 0.9], # 1
1960
]
1961
lines = Lines(linewidth=linewidth, vertices=vertices, colors=colors)
1962
1963
linewidth2 = 3
1964
vertices2 = [
1965
[[0.5, 0.5, 0.0], [0.7, 0.5, 0.0], [0.7, 1.0, 0.0]], # 0 green
1966
[[0.8, 0.5, 0.0], [0.9, 0.8, 0.0], [0.8, 0.2, 0.0]], # 1 orange
1967
]
1968
colors2 = [
1969
[0.0, 0.9, 0.3, 0.9], # 0
1970
[0.9, 0.3, 0.0, 0.9], # 1
1971
]
1972
triangles = Triangles(linewidth=linewidth2, vertices=vertices2, colors=colors2)
1973
1974
linewidth3 = 3
1975
vertices3 = [
1976
[[0.5, 0.0, 0.0], [0.7, 0.0, 0.0], [0.7, 0.3, 0.0], [0.5, 0.3, 0.0], ], # 0
1977
[[0.1, 0.0, 0.0], [0.3, 0.0, 0.0], [0.3, 0.2, 0.0], [0.1, 0.2, 0.0], ], # 1
1978
]
1979
colors3 = [
1980
[0.8, 0.0, 0.8, 0.9], # 0
1981
[0.0, 0.6, 0.6, 0.9], # 1
1982
]
1983
rectangles = Rectangles(linewidth=linewidth3, vertices=vertices3, colors=colors3)
1984
1985
if __name__ == '__main__':
1986
1987
app = wx.PySimpleApp()
1988
1989
if 1:
1990
1991
frame = TestMainframe()
1992
gleditor = frame.add_view('GL Editor', GlEditor)
1993
#gleditor = frame._splitter.add_view('GL Editor',GlEditor)
1994
frame.Show()
1995
frame.on_size()
1996
canvas = gleditor.get_canvas()
1997
canvas.add_element(lines)
1998
canvas.add_element(triangles)
1999
canvas.add_element(rectangles)
2000
2001
app.SetTopWindow(frame)
2002
app.MainLoop()
2003
2004
app.Destroy()
2005
2006