1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """The glue between the main application and the simulation. This job
23 is achieved by the L{Manager} that coordinates GTK events with a VTK area.
24 """
25 import gtk
26 import gobject
27
28 from mbdyn.interface.nodes import NodeMenu
29 from mbdyn.interface.references import ReferenceFrameMenu
30 from mbdyn.interface.groups import ReferenceListMenu
31 from mbdyn.interface.vectors import ReferenceFrame as vtkReferenceFrame
32
33 from windSimSuite.interface.tower import TowerMenu
34 from windSimSuite.interface.nacelle import NacelleMenu
35 from windSimSuite.interface.rotor import HubMenu, RotorMenu
36 from windSimSuite.interface.blade import BladeMenu
37 from windSimSuite.interface.sections import SectionMenu
38
39 from windSimSuite.interface.vtk_area import GtkVtkArea
40 from windSimSuite.interface.matplotlib_manager import FigureManager
41 from windSimSuite.interface.main import PyMBDynFile
42
43 from mbdyn.interface.vectors import Arrow as ArrowMapper
44
45 MENU_TABLE = {}
46 MENU_TABLE["node"] = NodeMenu()
47 MENU_TABLE["reference_frame"] = ReferenceFrameMenu()
48
49 MENU_TABLE["reference_list"] = ReferenceListMenu()
50
51 MENU_TABLE["tower"] = TowerMenu()
52 MENU_TABLE["nacelle"] = NacelleMenu()
53 MENU_TABLE["rotor"] = RotorMenu()
54 MENU_TABLE["hub"] = HubMenu()
55 MENU_TABLE["blade"] = BladeMenu()
56 MENU_TABLE["section"] = SectionMenu()
57
58
60 """A table for scaling the simulation in 3D.
61 This table is shared between the simulation
62 and the manager"""
63
64 - def __init__(self, widgets, win_interactor):
65 self.widget = widgets["scale_table"]
66 self.spin = {}
67 for key in ["scale_factor", "unit_vector"]:
68 self.spin[key] = widgets["spinbutton_" + key]
69 self.spin[key].connect("activate", self.redraw)
70
71 self.spin["scale_factor"].set_value(0.2)
72 self.spin["unit_vector"].set_value(5.)
73
74 self.win_interactor = win_interactor
75
76 self.objs = []
77 self.vectors = []
78
79 - def redraw(self, spinbutton=None):
80 """Redraw all the objects. They are contained in C{objs} attribute,
81 a new scale factor is set and a new definition of the unit length
82 is given"""
83 for obj in self.objs + self.vectors:
84 obj.set_scale_factor(self.spin["scale_factor"].get_value())
85 for vector in self.vectors:
86 vector.set_norm(self.spin["unit_vector"].get_value())
87 self.win_interactor.Render()
88
90 """Add the reference of an object to scale,
91 from the simulation"""
92 self.objs.append(obj)
93
95 """Add a vector to scale"""
96 self.vectors.append(obj)
97
99 """Reset for a new simulation"""
100 self.objs = []
101 self.vectors = []
102
104 """Show the scale table"""
105 self.widget.show()
106
108 """Hide the scale table"""
109 self.widget.hide()
110
111
113 """A custom GTK status bar. It does not need any context id
114 to write something, the message_id is then kept
115 for cleaning. This C{StatusBar} is shared between
116 the widgets to express their operations to the interface.
117 """
118
120 self.widget = widget
121 desc = "Wind sim suite actions"
122 self.context_id = self.widget.get_context_id(desc)
123 self.message_id = self.widget.push(self.context_id, "")
124
125 - def write(self, message):
126 """Write a message on the status bar"""
127 self._clean()
128 self.message_id = self.widget.push(self.context_id, message)
129
131 """Clean the status bar"""
132 self.widget.remove(self.context_id, self.message_id)
133
134
136 """A GTK treeview filled of simulation objects
137 """
138
139 - def __init__(self, status_bar, title="Wind turbine"):
140 self.model = gtk.TreeStore(gobject.TYPE_PYOBJECT,
141 gobject.TYPE_STRING)
142 gtk.TreeView.__init__(self, self.model)
143
144 self.status_bar = status_bar
145
146 self.set_rules_hint(True)
147
148 self.column_id = {"obj" : 0, "text" : 1}
149 renderer = gtk.CellRendererText()
150 column = gtk.TreeViewColumn(title,
151 renderer,
152 text=self.column_id["text"])
153 self.append_column(column)
154
158
160 """Return the object reference in case of a right click"""
161 if event.button == 3:
162 xpos, ypos = map(int, [event.x, event.y])
163 try:
164 path, col, cellx, celly = self.get_path_at_pos(xpos, ypos)
165 except TypeError:
166 return True
167 selection = self.get_selection()
168 if not selection.path_is_selected(path):
169 self.set_cursor(path, col, 0)
170
171 model, giter = selection.get_selected()
172 if giter:
173 return model.get_value(giter, self.column_id["obj"])
174 else:
175 return None
176
178 """Clear the model for welcoming a new simulation"""
179 self.model.clear()
180
182 """Return the C{TreeIter} instance at the top"""
183 return self.model.append(None)
184
186 """Return the C{TreeIter} instance from the one given"""
187 return self.model.append(giter)
188
189 - def add_at(self, giter, obj):
190 """Add an object at a particular C{TreeIter} instance"""
191 self.model.set(giter, self.column_id["obj"], obj)
192 self.model.set(giter, self.column_id["text"], obj.name)
193
194
358
359
361 """A class managing the wind turbine simulation instance with
362 the VTK area and the GTK area (or interface).
363
364 For the MBDyn interfacing, the VTK area is defined by
365 C{GtkVtkArea} from the L{windSimSuite.interface.vtk_area} module,
366 displaying the turbine in 3D. The GTK area is defined by the L{TreeView},
367 displaying the turbine with GTK cells on which the user can right click.
368
369 However the GTK area is doing more as figures can also be output from
370 the Matplotlib interface. The C{Manager} is also taking care of the notebook,
371 displaying a new page when a new figure is drawn, thanks to
372 the C{FigureManager} from the L{windSimSuite.interface.matplotlib_manager}.
373 The C{Manager} can also hide the VTK area, contained in the notebook
374 if nothing is available for a 3D view."""
375
377 self.status_bar = StatusBar(widgets["statusbar"])
378
379
380 self.vtk_area = GtkVtkArea(self.status_bar)
381 self.vtk_area.set_on_right_click(self.show_menu)
382 self.vtk_area.set_on_motion_notify_event(self.track_actors)
383 self.win_interactor = self.vtk_area.win_interactor
384
385
386
387 self.treeview = {}
388 for key, title in zip(["turbine", "mbdyn"],
389 ["Wind turbine", "MBDyn objects"]):
390 tvw = TreeView(self.status_bar, title)
391 tvw.connect_button_press_event(self.show_menu)
392 tvw.show()
393 self.treeview[key] = tvw
394
395 self.notebook = widgets["notebook"]
396 self.fig_manager = FigureManager(self.notebook,
397 self.status_bar)
398 self.fig_manager.set_window_ref(widgets["application"])
399
400 self.menu_table = MENU_TABLE
401 for menu in MENU_TABLE.values():
402 for prop_key in menu.properties["vtk"]:
403 menu.connect_with_key(prop_key,
404 self.set_obj_boolean_for_vtk)
405 for prop_key in menu.properties["pylab"]:
406 menu.connect_with_key(prop_key,
407 self.plot_obj)
408
409 self.simu = None
410 self.obj = None
411
412 self.anim = AnimationToolbar(self.win_interactor,
413 self.status_bar,
414 widgets)
415
416 self.progress_bar = widgets["progressbar"]
417 self.progress_bar.hide()
418 self.task_box = widgets["task_box"]
419
420 self.absolute_ref = vtkReferenceFrame()
421 unit_arrow = ArrowMapper()
422 self.absolute_ref.set_arrow(unit_arrow)
423 self.scale_table = ScaleTable(widgets, self.win_interactor)
424 self.scale_table.add_vector(unit_arrow)
425 self.show_absolute_ref()
426
428 """Show the action menu.
429 Called when button-press-event, with event=3,
430 is emitted by the GtkVTKSelector area or one
431 of the treeviews.
432 There is still a problem with True/False for the
433 VTK area?"""
434 obj = area.get_object(event)
435 if obj == None:
436 return False
437 else:
438 self.obj = obj
439 menu = self.menu_table[obj.menu_type]
440 menu.set_for(obj)
441 menu.custom_popup(event)
442 return True
443
445 """Track the VTK actors.
446 Act on 'motion_notify_event' emitted by the GtkVTKSelector"""
447 obj = self.vtk_area.get_object(event)
448 if obj == None:
449 self.vtk_area.remove_items()
450 else:
451 self.obj = obj
452 self.vtk_area.add_item(self.obj)
453 self.win_interactor.Render()
454
456 """Update the properties of an object for the VTK area.
457
458 The action can be called by right click on the GTK area
459 (in the Treeview) or from the VTK area.
460 """
461 if gtk_check_item.get_active():
462 if not self.obj.boolean[key]:
463 status = self.obj.activate(key,
464 self.anim.current_frame_id,
465 self.vtk_area)
466 self.status_bar.write(status)
467 else:
468 if self.obj.boolean[key]:
469 status = self.obj.desactivate(key,
470 self.vtk_area)
471 self.status_bar.write(status)
472 self.win_interactor.Render()
473
474
475 return False
476
478 """Update the properties of an object for the VTK area.
479
480 The action can be called by right click on the GTK area
481 (in the Treeview) or from the VTK area.
482 """
483 status = self.fig_manager.plot(key, self.obj, self.simu)
484 self.status_bar.write(status)
485 return False
486
488 """Load the simulation by a generator object. This
489 method does not work as expected, there is still lot of
490 work for the loading process of every object."""
491 self.task_box.show()
492 yield True
493 if self.simu != None:
494 self.vtk_area.clean()
495 pyf = PyMBDynFile(filename)
496 yield True
497 self.simu = pyf.simulations[0]
498 pyf.close()
499 yield True
500 self.simu.turbine.display_on(self.treeview["turbine"])
501 yield True
502 self.simu.display_on(self.treeview["mbdyn"])
503 yield True
504 self.simu.set_scale_table(self.scale_table)
505 self.simu.create_vtk_actors()
506 self.absolute_ref.set_arrow(self.simu.unit_arrow)
507 yield True
508 self.simu.add_actors_to_select(self.vtk_area)
509 yield True
510 self.simu.init_from_loaded_file()
511 yield True
512 self.anim.set_simulation(self.simu)
513 self.task_box.hide()
514 yield False
515
517 """Show the absolute reference frame"""
518 for axe in self.absolute_ref.axes:
519 self.vtk_area.renderer.AddActor(axe.actor)
520 self.win_interactor.Render()
521
523 """Hide the absolute reference frame"""
524 for axe in self.absolute_ref.axes:
525 self.vtk_area.renderer.RemoveActor(axe.actor)
526 self.win_interactor.Render()
527