1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3# vim: set fileencoding=utf-8
4
5## EXTRAITS DE LA LICENCE
6## Copyright CEA, contributeurs : Damien CALISTE, laboratoire L_Sim, (2012-2012)
7## Adresse mèl :
8## CALISTE, damien P caliste AT cea P fr.
9
10## Ce logiciel est un programme informatique servant à visualiser des
11## structures atomiques dans un rendu pseudo-3D.
12## Ce logiciel est régi par la licence CeCILL soumise au droit français et
13## respectant les principes de diffusion des logiciels libres. Vous pouvez
14## utiliser, modifier et/ou redistribuer ce programme sous les conditions
15## de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
16## sur le site "http://www.cecill.info".
17## Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
18## pris connaissance de la licence CeCILL, et que vous en avez accepté les
19## termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
20
21## LICENCE SUM UP
22## Copyright CEA, contributors: Damien CALISTE, L_Sim laboratory, (2012-2012)
23## E-mail address:
24## CALISTE, damien P caliste AT cea P fr.
25
26## This software is a computer program whose purpose is to visualize atomic
27## configurations in 3D.
28## This software is governed by the CeCILL  license under French law and
29## abiding by the rules of distribution of free software.  You can  use,
30## modify and/ or redistribute the software under the terms of the CeCILL
31## license as circulated by CEA, CNRS and INRIA at the following URL
32## "http://www.cecill.info".
33## The fact that you are presently reading this means that you have had
34## knowledge of the CeCILL license and that you accept its terms. You can
35## find a copy of this licence shipped with this software at
36## Documentation/licence.en.txt.
37
38from gi.repository import v_sim
39from gi.repository import Gtk
40
41import numpy
42
43from matplotlib.figure import Figure
44from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas
45from matplotlib.backends.backend_cairo import RendererCairo as Renderer
46
47dpi = 100
48fig_width = 3
49fig_height = 2
50
51def mplCurveDraw(widget, cr, f, renderer):
52  renderer.gc.ctx = cr
53  w = widget.get_allocated_width()
54  h = widget.get_allocated_height()
55  cr.translate(max(0, (w - fig_width * dpi) * 0.5),
56               -max(0, (h - fig_height * dpi) * 0.5))
57  renderer.set_width_height(w, h)
58  f.draw(renderer)
59
60def onTogglePick(widget, interPick, panel, wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref):
61  render = v_sim.UiMainClass.getDefaultRendering()
62  if (widget.get_active()):
63    handle = interPick.connect("node-selection", onNodeSelected, panel, widget,
64                               wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref)
65    interPick.set_data("pick", handle)
66    render.pushInteractive(interPick)
67    render.pushMessage("Pick a node with the mouse")
68  else:
69    interPick.disconnect(interPick.get_data("pick"))
70    render.popInteractive(interPick)
71    render.popMessage()
72
73def onNodeSelected(inter, kind, node0, node1, node2, panel, toggle,
74                   entryX, entryY, entryZ, entryX_ref, entryY_ref, entryZ_ref):
75  if not(kind == v_sim.InteractivePick.SELECTED):
76    return
77
78  data = panel.getData()
79  (x, y, z) = data.getNodeCoordinates(node0)
80  if entryX_ref is not None:
81    entryX.setValue(x - entryX_ref.getValue())
82  else:
83    entryX.setValue(x)
84  if entryY_ref is not None:
85    entryY.setValue(y - entryY_ref.getValue())
86  else:
87    entryY.setValue(y)
88  if entryZ_ref is not None:
89    entryZ.setValue(z - entryZ_ref.getValue())
90  else:
91    entryZ.setValue(z)
92  toggle.set_active(False)
93
94def onDraw(widget, area, mplFig, panel, combo, (ox, oy, oz), (dx, dy, dz)):
95  # We get the scalar field.
96  it = combo.get_active_iter()
97  if it is None:
98    return
99  model = combo.get_model()
100  (field,) = model.get(it, v_sim.UiSurfacesFieldId.POINTER)
101  data = panel.getData()
102
103  # We setup the data to iterate over.
104  orig = numpy.array(data.convertXYZToReduced((ox.getValue(), oy.getValue(), oz.getValue())))
105  vect = numpy.array(data.convertXYZToReduced((dx.getValue(), dy.getValue(), dz.getValue())))
106  norm = 1. / numpy.sqrt(vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2])
107  vect *= norm
108  l0 = max(-orig[0] / max(vect[0], 1e-6), -orig[1] / max(vect[1], 1e-6), -orig[2] / max(vect[2], 1e-6))
109  l1 = min((1. - orig[0]) / max(vect[0], 1e-6), (1. - orig[1]) / max(vect[1], 1e-6), (1. - orig[2]) / max(vect[2], 1e-6))
110  orig0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l0 * vect)))
111  vect0 = numpy.array(data.convertReducedToXYZ(tuple(orig + l1 * vect))) - orig0
112  norm = numpy.sqrt(vect0[0] * vect0[0] + vect0[1] * vect0[1] + vect0[2] * vect0[2])
113
114  # We setup the data to be plotted.
115  a = mplFig.add_subplot(111)
116  x = numpy.arange(0.0, 1.0, 0.01)
117  y = numpy.arange(0.0, 1.0, 0.01)
118  for i in range(100):
119    point = orig0 + x[i] * vect0
120    (valid, val) = field.getValue(tuple(point), (0,0,0))
121    if valid:
122      y[i] = val
123  x *= norm
124  a.plot(x,y)
125  # We ask for redraw of the widget.
126  area.queue_draw()
127
128def panelCreateSelection(panel, vbox, interPick, label,
129                         wdx_ref = None, wdy_ref = None, wdz_ref = None):
130  # The line to choose the origin/orientation.
131  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
132  vbox.pack_start(hbox, False, False, 0)
133
134  lbl = Gtk.Label.new(label)
135  hbox.pack_start(lbl, False, False, 0)
136
137  wdx = v_sim.UiNumericalEntry.new(0.)
138  wdx.set_width_chars(6)
139  hbox.pack_start(wdx, True, True, 0)
140  wdy = v_sim.UiNumericalEntry.new(0.)
141  wdy.set_width_chars(6)
142  hbox.pack_start(wdy, True, True, 0)
143  wdz = v_sim.UiNumericalEntry.new(0.)
144  wdz.set_width_chars(6)
145  hbox.pack_start(wdz, True, True, 0)
146
147  wd = Gtk.ToggleButton.new()
148  wd.add(Gtk.Image.new_from_stock(Gtk.STOCK_FIND, Gtk.IconSize.MENU))
149  wd.connect("toggled", onTogglePick, interPick, panel,
150             wdx, wdy, wdz, wdx_ref, wdy_ref, wdz_ref)
151  hbox.pack_start(wd, False, False, 0)
152
153  return (wdx, wdy, wdz)
154
155def panelCreateWidgets():
156  panel = v_sim.UiPanel.new("mytools", "Customized tools", "My tools")
157  panel.setDockable(True)
158  panel.attach(v_sim.UiPanelClass.getCommandPanel());
159
160  vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
161  panel.add(vbox)
162
163  lbl = Gtk.Label.new("<b>Interpolate data along lines</b>")
164  lbl.set_alignment(0., 0.5)
165  lbl.set_use_markup(True)
166  vbox.pack_start(lbl, False, False, 0)
167
168  # The line to choose a data field.
169  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5)
170  vbox.pack_start(hbox, False, False, 0)
171
172  lbl = Gtk.Label.new("Choose a data field:")
173  hbox.pack_start(lbl, False, False, 0)
174
175  combo = Gtk.ComboBox.new()
176  combo.set_model(v_sim.UiPanel.surfaces_getFields())
177  hbox.pack_start(combo, True, True, 0)
178  renderer = Gtk.CellRendererText.new()
179  combo.pack_start(renderer, False)
180  renderer.set_property("xalign", 1.0)
181  combo.add_attribute(renderer, "markup", v_sim.UiSurfacesFieldId.LABEL)
182
183  interPick = v_sim.Interactive.new(v_sim.InteractiveId.PICK)
184
185  # The line to choose the origin.
186  (origx, origy, origz) = panelCreateSelection(panel, vbox, interPick,
187                                               "Choose the origin:")
188
189  # The line to choose the direction.
190  (dirx, diry, dirz) = panelCreateSelection(panel, vbox, interPick,
191                                            "Choose the direction:",
192                                            wdx_ref = origx, wdy_ref = origy,
193                                            wdz_ref = origz)
194  dirx.setValue(1.)
195  diry.setValue(1.)
196  dirz.setValue(1.)
197
198  # The drawing area for the curve.
199  hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
200  vbox.pack_start(hbox, True, True, 0)
201
202  scrolled = Gtk.ScrolledWindow.new(None, None)
203  scrolled.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
204  hbox.pack_start(scrolled, True, True, 0)
205
206  f = Figure(figsize=(fig_width,fig_height), dpi = dpi)
207  canvas = FigureCanvas(f)
208  f.set_canvas(canvas)
209  renderer = Renderer(dpi = dpi)
210
211  area = Gtk.DrawingArea.new()
212  area.set_size_request(fig_width * dpi, fig_height * dpi)
213  area.connect("draw", mplCurveDraw, f, renderer)
214  scrolled.add_with_viewport(area)
215
216  # The toolbar for action on the curve.
217  wd = Gtk.Toolbar.new()
218  wd.set_orientation(Gtk.Orientation.VERTICAL)
219  wd.set_style(Gtk.ToolbarStyle.ICONS)
220  wd.set_icon_size(Gtk.IconSize.SMALL_TOOLBAR)
221  hbox.pack_start(wd, False, False, 0)
222
223  item = Gtk.ToolButton.new_from_stock(Gtk.STOCK_REFRESH)
224  item.connect("clicked", onDraw, area, f, panel, combo,
225               (origx, origy, origz), (dirx, diry, dirz))
226  wd.insert(item, -1)
227
228  return (f, panel, interPick)
229
230# We create the widgets and plot the stuff.
231(mplFig, panel, i) = panelCreateWidgets()
232panel.show_all()
233
234