1 /* EXTRAITS DE LA LICENCE
2 Copyright CEA, contributeurs : Luc BILLARD et Damien
3 CALISTE, laboratoire L_Sim, (2001-2005)
4
5 Adresse mèl :
6 BILLARD, non joignable par mèl ;
7 CALISTE, damien P caliste AT cea P fr.
8
9 Ce logiciel est un programme informatique servant à visualiser des
10 structures atomiques dans un rendu pseudo-3D.
11
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
18 Le fait que vous puissiez accéder à cet en-tête signifie que vous avez
19 pris connaissance de la licence CeCILL, et que vous en avez accepté les
20 termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
21 */
22
23 /* LICENCE SUM UP
24 Copyright CEA, contributors : Luc BILLARD et Damien
25 CALISTE, laboratoire L_Sim, (2001-2005)
26
27 E-mail address:
28 BILLARD, not reachable any more ;
29 CALISTE, damien P caliste AT cea P fr.
30
31 This software is a computer program whose purpose is to visualize atomic
32 configurations in 3D.
33
34 This software is governed by the CeCILL license under French law and
35 abiding by the rules of distribution of free software. You can use,
36 modify and/ or redistribute the software under the terms of the CeCILL
37 license as circulated by CEA, CNRS and INRIA at the following URL
38 "http://www.cecill.info".
39
40 The fact that you are presently reading this means that you have had
41 knowledge of the CeCILL license and that you accept its terms. You can
42 find a copy of this licence shipped with this software at Documentation/licence.en.txt.
43 */
44 #include "visu_data.h"
45
46
47 #include <string.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <math.h>
51
52 #include "visu_commandLine.h"
53 #include "extraFunctions/idProp.h"
54 #include "extraFunctions/typeProp.h"
55 #include "extraFunctions/coordProp.h"
56 #include "extraFunctions/geometry.h"
57 #include "extraFunctions/vibration.h"
58 #include "coreTools/toolMatrix.h"
59
60 /**
61 * SECTION:visu_data
62 * @short_description: Give methods to store and manage data from
63 * input file(s).
64 *
65 * <para>The main goal of V_Sim is to draw lists of elements. For
66 * example, when used to render atoms, a box that contains 24 silicon
67 * atoms and 46 germanium atoms is a box with two elements (silicon
68 * and germanium) where the silicon element has 24 nodes and the
69 * germanium element has 46 nodes. This module gives then methods to
70 * create nodes (see #VisuElement to create and managed
71 * elements).</para>
72 *
73 * <para>All nodes are stored in a structure called #VisuNodeArray and
74 * #VisuNodeArray is encapsulated in a #VisuData for all not-node related
75 * information. V_Sim uses one #VisuData per input file(s). This
76 * structure contains a list of pointers on all the #VisuElement used
77 * in this file.</para>
78 *
79 * <para>To iterate on nodes, one should use the provided iterators
80 * (see #VisuNodeArrayIter) methods, like visu_node_array_iter_next().</para>
81 */
82
83 enum {
84 NODE_PROP_ADDED_SIGNAL,
85 NODE_PROP_REMOVED_SIGNAL,
86 LAST_SIGNAL
87 };
88
89 enum
90 {
91 PROP_0,
92 DESCR_PROP,
93 TOTAL_ENERGY_PROP,
94 N_PROP,
95 TRANS_PROP,
96 RED_TRANS_PROP,
97 USE_TRANS_PROP,
98 MODULO_PROP,
99 BOX_PROP,
100 ADJUST_PROP
101 };
102 static GParamSpec *properties[N_PROP];
103
104 struct _VisuDataPrivate
105 {
106 gboolean dispose_has_run;
107
108 gchar* commentary;
109
110 /******************/
111 /* Box attributes */
112 /******************/
113 VisuBox *box;
114 float extension[3];
115 gulong unit_signal, expand_signal, expAct_signal;
116 /* Translation applied to all nodes when rendered. */
117 gboolean inTheBox, inTheBox_replicate;
118 gboolean translationActive;
119 float translation[3];
120
121 /********************/
122 /* Misc. attributes */
123 /********************/
124 /* The total energy of the system in eV. */
125 gdouble totalEnergy;
126 /* The list of known VisuNodeValues. */
127 GHashTable *nodeProperties;
128 };
129
130
131 static void visu_data_dispose (GObject* obj);
132 static void visu_data_finalize (GObject* obj);
133 static void visu_data_get_property(GObject* obj, guint property_id,
134 GValue *value, GParamSpec *pspec);
135 static void visu_data_set_property(GObject* obj, guint property_id,
136 const GValue *value, GParamSpec *pspec);
137 static gboolean _inTheBox(VisuPointset *self, gboolean status);
138 static void _getTranslation(VisuPointset *self, float trans[3]);
139 static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo);
140 static gboolean _setTranslationActive(VisuPointset *self, gboolean status);
141 static void _applyTranslation(VisuPointset *self);
142 static void visu_boxed_interface_init(VisuBoxedInterface *iface);
143 static void visu_pointset_interface_init(VisuPointsetInterface *iface);
144
145 /* Local callbacks. */
146 static void onBoxUnitChanged(VisuData *data, gfloat fact);
147 static void onBoxExtensChanged(VisuBox *box, GParamSpec *pspec, gpointer user_data);
148 static void onBoxExtensActive(VisuBox *box, GParamSpec *pspec, gpointer user_data);
149
150 /* Local routines. */
151 static VisuBox* visu_data_getBox(VisuBoxed *self);
152 static gboolean visu_data_setBox(VisuBoxed *self, VisuBox *box);
153 static GArray* shrinkNodeList(VisuData *data, int coord, float valueTo);
154 static void extendNodeList(VisuData *data, int coord, float valueFrom, float valueTo);
155 static void _replicate(VisuData *data, gfloat extension[3]);
156 static gboolean _constrainedInTheBox(VisuData *data, gboolean emit);
157 static gboolean _constrainedFree(VisuData *data, gboolean emit);
158
159 static guint visu_data_signals[LAST_SIGNAL] = { 0 };
160
G_DEFINE_TYPE_WITH_CODE(VisuData,visu_data,VISU_TYPE_NODE_ARRAY,G_ADD_PRIVATE (VisuData)G_IMPLEMENT_INTERFACE (VISU_TYPE_BOXED,visu_boxed_interface_init)G_IMPLEMENT_INTERFACE (VISU_TYPE_POINTSET,visu_pointset_interface_init))161 G_DEFINE_TYPE_WITH_CODE(VisuData, visu_data, VISU_TYPE_NODE_ARRAY,
162 G_ADD_PRIVATE(VisuData)
163 G_IMPLEMENT_INTERFACE(VISU_TYPE_BOXED,
164 visu_boxed_interface_init)
165 G_IMPLEMENT_INTERFACE(VISU_TYPE_POINTSET,
166 visu_pointset_interface_init))
167
168 static void visu_data_class_init(VisuDataClass *klass)
169 {
170 DBG_fprintf(stderr, "Visu Data: creating the class of the object.\n");
171 DBG_fprintf(stderr, " - adding new signals ;\n");
172 /**
173 * VisuData::node-properties-added:
174 * @dataObj: the object which received the signal ;
175 * @values: a #VisuNodeValues object.
176 *
177 * Gets emitted when @values node properties is added to @dataObj.
178 *
179 * Since: 3.8
180 */
181 visu_data_signals[NODE_PROP_ADDED_SIGNAL] =
182 g_signal_new("node-properties-added", G_TYPE_FROM_CLASS(klass),
183 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
184 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
185 G_TYPE_NONE, 1, VISU_TYPE_NODE_VALUES, NULL);
186
187 /**
188 * VisuData::node-properties-removed:
189 * @dataObj: the object which received the signal ;
190 * @values: a #VisuNodeValues object.
191 *
192 * Gets emitted when @values node properties is removed from @dataObj.
193 *
194 * Since: 3.8
195 */
196 visu_data_signals[NODE_PROP_REMOVED_SIGNAL] =
197 g_signal_new("node-properties-removed", G_TYPE_FROM_CLASS(klass),
198 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
199 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
200 G_TYPE_NONE, 1, VISU_TYPE_NODE_VALUES, NULL);
201
202 /* Connect the overloading methods. */
203 G_OBJECT_CLASS(klass)->dispose = visu_data_dispose;
204 G_OBJECT_CLASS(klass)->finalize = visu_data_finalize;
205 G_OBJECT_CLASS(klass)->set_property = visu_data_set_property;
206 G_OBJECT_CLASS(klass)->get_property = visu_data_get_property;
207
208 /**
209 * VisuData::description:
210 *
211 * Store a description for the data.
212 *
213 * Since: 3.8
214 */
215 properties[DESCR_PROP] =
216 g_param_spec_string("description", "Description", "a description of the data",
217 "", G_PARAM_READWRITE);
218 /**
219 * VisuData::totalEnergy:
220 *
221 * Store the total energy of the system in eV.
222 *
223 * Since: 3.6
224 */
225 properties[TOTAL_ENERGY_PROP] =
226 g_param_spec_double("totalEnergy", "Total energy", "Total energy of the system (eV)",
227 -G_MAXFLOAT, G_MAXFLOAT, G_MAXFLOAT,
228 G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
229
230 g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties);
231
232 g_object_class_override_property(G_OBJECT_CLASS(klass), USE_TRANS_PROP, "use-translation");
233 g_object_class_override_property(G_OBJECT_CLASS(klass), TRANS_PROP, "translation");
234 g_object_class_override_property(G_OBJECT_CLASS(klass), RED_TRANS_PROP, "reduced-translation");
235 g_object_class_override_property(G_OBJECT_CLASS(klass), MODULO_PROP, "in-the-box");
236 g_object_class_override_property(G_OBJECT_CLASS(klass), ADJUST_PROP, "auto-adjust");
237 g_object_class_override_property(G_OBJECT_CLASS(klass), BOX_PROP, "box");
238 }
visu_boxed_interface_init(VisuBoxedInterface * iface)239 static void visu_boxed_interface_init(VisuBoxedInterface *iface)
240 {
241 iface->get_box = visu_data_getBox;
242 iface->set_box = visu_data_setBox;
243 }
visu_pointset_interface_init(VisuPointsetInterface * iface)244 static void visu_pointset_interface_init(VisuPointsetInterface *iface)
245 {
246 iface->set_inTheBox = _inTheBox;
247 iface->apply_translation = _applyTranslation;
248 iface->get_translation = _getTranslation;
249 iface->set_translation = _setTranslation;
250 iface->set_translationActive = _setTranslationActive;
251 }
252
visu_data_init(VisuData * obj)253 static void visu_data_init(VisuData *obj)
254 {
255 DBG_fprintf(stderr, "Visu Data: initializing a new object (%p).\n",
256 (gpointer)obj);
257
258 obj->priv = visu_data_get_instance_private(obj);
259 obj->priv->dispose_has_run = FALSE;
260
261 /* Private data. */
262 obj->priv->commentary = g_strdup("");
263 obj->priv->box = (VisuBox*)0;
264 obj->priv->unit_signal = 0;
265 obj->priv->expand_signal = 0;
266 obj->priv->extension[0] = 0.f;
267 obj->priv->extension[1] = 0.f;
268 obj->priv->extension[2] = 0.f;
269 obj->priv->inTheBox = FALSE;
270 obj->priv->inTheBox_replicate = FALSE;
271 obj->priv->translationActive = FALSE;
272 obj->priv->translation[0] = 0.f;
273 obj->priv->translation[1] = 0.f;
274 obj->priv->translation[2] = 0.f;
275 obj->priv->nodeProperties = g_hash_table_new_full(g_str_hash, g_str_equal,
276 NULL,
277 (GDestroyNotify)g_object_unref);;
278
279 /* Ensure that the base (label, ...) property exists. */
280 visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_id_new(VISU_NODE_ARRAY(obj))));
281 visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_type_new(VISU_NODE_ARRAY(obj))));
282 visu_data_addNodeProperties(obj, VISU_NODE_VALUES(visu_node_values_coord_new(obj)));
283 visu_data_getNodeLabels(obj);
284 }
285
286 /* This method can be called several times.
287 It should unref all of its reference to
288 GObjects. */
visu_data_dispose(GObject * obj)289 static void visu_data_dispose(GObject* obj)
290 {
291 VisuData *data;
292
293 DBG_fprintf(stderr, "Visu Data: dispose object %p.\n", (gpointer)obj);
294
295 data = VISU_DATA(obj);
296 if (data->priv->dispose_has_run)
297 return;
298 data->priv->dispose_has_run = TRUE;
299
300 visu_data_setBox(VISU_BOXED(data), (VisuBox*)0);
301
302 /* Chain up to the parent class */
303 G_OBJECT_CLASS(visu_data_parent_class)->dispose(obj);
304 }
305 /* This method is called once only. */
visu_data_finalize(GObject * obj)306 static void visu_data_finalize(GObject* obj)
307 {
308 VisuData *data;
309
310 g_return_if_fail(obj);
311
312 DBG_fprintf(stderr, "Visu Data: finalize object %p.\n", (gpointer)obj);
313
314 data = VISU_DATA(obj);
315
316 /* Free privs elements. */
317 if (data->priv)
318 {
319 DBG_fprintf(stderr, "Visu data: free private data.\n");
320 g_free(data->priv->commentary);
321 g_hash_table_destroy(data->priv->nodeProperties);
322 }
323 /* The free is called by g_type_free_instance... */
324 /* g_free(data); */
325
326 /* Chain up to the parent class */
327 DBG_fprintf(stderr, "Visu data: chain to parent.\n");
328 G_OBJECT_CLASS(visu_data_parent_class)->finalize(obj);
329 DBG_fprintf(stderr, "Visu data: freeing ... OK.\n");
330 }
visu_data_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)331 static void visu_data_get_property(GObject* obj, guint property_id,
332 GValue *value, GParamSpec *pspec)
333 {
334 VisuData *self = VISU_DATA(obj);
335 gfloat *redTrans;
336
337 DBG_fprintf(stderr, "Visu Data: get property '%s' -> ",
338 g_param_spec_get_name(pspec));
339 switch (property_id)
340 {
341 case DESCR_PROP:
342 g_value_set_string(value, self->priv->commentary);
343 DBG_fprintf(stderr, "%s.\n", self->priv->commentary);
344 break;
345 case TOTAL_ENERGY_PROP:
346 g_value_set_double(value, self->priv->totalEnergy);
347 DBG_fprintf(stderr, "%geV.\n", self->priv->totalEnergy);
348 break;
349 case USE_TRANS_PROP:
350 g_value_set_boolean(value, self->priv->translationActive);
351 DBG_fprintf(stderr, "%d.\n", self->priv->translationActive);
352 break;
353 case TRANS_PROP:
354 g_value_set_static_boxed(value, self->priv->translation);
355 DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]);
356 break;
357 case RED_TRANS_PROP:
358 redTrans = g_malloc(sizeof(gfloat) * 3);
359 visu_box_convertXYZtoBoxCoordinates(self->priv->box,
360 redTrans, self->priv->translation);
361 g_value_take_boxed(value, redTrans);
362 DBG_fprintf(stderr, "%gx%gx%g.\n", redTrans[0], redTrans[1], redTrans[2]);
363 break;
364 case MODULO_PROP:
365 g_value_set_boolean(value, self->priv->inTheBox);
366 DBG_fprintf(stderr, "%d.\n", self->priv->inTheBox);
367 break;
368 case BOX_PROP:
369 g_value_set_object(value, self->priv->box);
370 DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->box);
371 break;
372 case ADJUST_PROP:
373 g_object_get_property(G_OBJECT(self->priv->box), "auto-adjust", value);
374 DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
375 break;
376 default:
377 /* We don't have any other property... */
378 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
379 break;
380 }
381 }
visu_data_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)382 static void visu_data_set_property(GObject* obj, guint property_id,
383 const GValue *value, GParamSpec *pspec)
384 {
385 VisuData *self = VISU_DATA(obj);
386
387 DBG_fprintf(stderr, "Visu Data: set property '%s' -> ",
388 g_param_spec_get_name(pspec));
389 switch (property_id)
390 {
391 case DESCR_PROP:
392 DBG_fprintf(stderr, "%s.\n", g_value_get_string(value));
393 visu_data_setDescription(self, g_value_get_string(value));
394 break;
395 case TOTAL_ENERGY_PROP:
396 self->priv->totalEnergy = g_value_get_double(value);
397 DBG_fprintf(stderr, "%geV.\n", self->priv->totalEnergy);
398 break;
399 case USE_TRANS_PROP:
400 visu_pointset_setTranslationActive(VISU_POINTSET(self),
401 g_value_get_boolean(value));
402 DBG_fprintf(stderr, "%d.\n", self->priv->translationActive);
403 break;
404 case TRANS_PROP:
405 visu_pointset_setTranslationPeriodic(VISU_POINTSET(self),
406 (gfloat*)g_value_get_boxed(value),
407 self->priv->inTheBox);
408 DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]);
409 break;
410 case RED_TRANS_PROP:
411 visu_pointset_setBoxTranslation(VISU_POINTSET(self),
412 (gfloat*)g_value_get_boxed(value),
413 self->priv->inTheBox);
414 DBG_fprintf(stderr, "%gx%gx%g.\n", self->priv->translation[0], self->priv->translation[1], self->priv->translation[2]);
415 break;
416 case MODULO_PROP:
417 visu_pointset_setInTheBox(VISU_POINTSET(self), g_value_get_boolean(value));
418 DBG_fprintf(stderr, "%d.\n", self->priv->inTheBox);
419 break;
420 case BOX_PROP:
421 DBG_fprintf(stderr, "%p.\n", g_value_get_object(value));
422 visu_data_setBox(VISU_BOXED(obj), VISU_BOX(g_value_get_object(value)));
423 break;
424 case ADJUST_PROP:
425 DBG_fprintf(stderr, "%d.\n", g_value_get_boolean(value));
426 g_object_set_property(G_OBJECT(self->priv->box), "auto-adjust", value);
427 break;
428 default:
429 /* We don't have any other property... */
430 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
431 break;
432 }
433 }
434
435
436 /**
437 * visu_data_new:
438 *
439 * This creates an empty #VisuData object.
440 *
441 * Returns: a newly created #VisuData object (its ref count is set to 1).
442 */
visu_data_new(void)443 VisuData* visu_data_new(void)
444 {
445 VisuData *data;
446
447 DBG_fprintf(stderr, "Visu Data: create a new VisuData object of type %d.\n",
448 (int)VISU_TYPE_DATA);
449 data = VISU_DATA(g_object_new(VISU_TYPE_DATA, NULL));
450
451 if (!data)
452 return (VisuData*)0;
453
454 return data;
455 }
456
457 /**
458 * visu_data_freePopulation:
459 * @data: a VisuData to be freed.
460 *
461 * This method frees only the allocated memory that deals with
462 * the nodes (i.e. everything except the data of the files,
463 * the properties and the setColor method.
464 */
visu_data_freePopulation(VisuData * data)465 void visu_data_freePopulation(VisuData *data)
466 {
467 float zeros[3] = {0.f, 0.f, 0.f};
468
469 if (!data)
470 return;
471
472 DBG_fprintf(stderr, "Visu Data: freeing the population of VisuData %p ...\n",
473 (gpointer)data);
474 visu_node_array_freeNodes(VISU_NODE_ARRAY(data));
475
476 if (data->priv->box)
477 {
478 visu_box_setExtension(data->priv->box, zeros);
479 visu_box_setExtensionActive(data->priv->box, FALSE);
480 visu_pointset_setTranslationPeriodic(VISU_POINTSET(data), zeros, FALSE);
481 }
482
483 DBG_fprintf(stderr, "Visu Data: freeing ... OK.\n");
484 }
485
486 /**
487 * visu_data_setDescription:
488 * @data: a #VisuData object ;
489 * @commentary: the message to be stored (null terminated) ;
490 *
491 * This method is used to store a description of the given @data. This
492 * string is copied and @commentary can be freed.
493 */
visu_data_setDescription(VisuData * data,const gchar * commentary)494 void visu_data_setDescription(VisuData *data, const gchar* commentary)
495 {
496 g_return_if_fail(VISU_IS_DATA(data));
497
498 g_free(data->priv->commentary);
499 data->priv->commentary = g_strdup(commentary);
500
501 g_object_notify_by_pspec(G_OBJECT(data), properties[DESCR_PROP]);
502 }
503
504 /**
505 * visu_data_getDescription:
506 * @data: a #VisuData object ;
507 *
508 * Get the commentary associated to the given @data.
509 *
510 * Returns: (transfer none): a string description (possibly
511 * empty). This string is own by V_Sim and should not be freed.
512 */
visu_data_getDescription(const VisuData * data)513 const gchar* visu_data_getDescription(const VisuData *data)
514 {
515 g_return_val_if_fail(VISU_IS_DATA(data), (gchar*)0);
516
517 return data->priv->commentary;
518 }
519
520 /*************************/
521 /* The geometry routines */
522 /*************************/
visu_data_getBox(VisuBoxed * self)523 static VisuBox* visu_data_getBox(VisuBoxed *self)
524 {
525 g_return_val_if_fail(VISU_IS_DATA(self), (VisuBox*)0);
526
527 return VISU_DATA(self)->priv->box;
528 }
visu_data_setBox(VisuBoxed * self,VisuBox * box)529 static gboolean visu_data_setBox(VisuBoxed *self, VisuBox *box)
530 {
531 VisuData *data;
532
533 g_return_val_if_fail(VISU_IS_DATA(self), FALSE);
534 data = VISU_DATA(self);
535
536 if (data->priv->box == box)
537 return FALSE;
538
539 if (data->priv->box)
540 {
541 g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->unit_signal);
542 g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->expand_signal);
543 g_signal_handler_disconnect(G_OBJECT(data->priv->box), data->priv->expAct_signal);
544 g_object_unref(data->priv->box);
545 }
546 data->priv->box = box;
547 if (box)
548 {
549 g_object_ref(box);
550 data->priv->unit_signal =
551 g_signal_connect_swapped(G_OBJECT(data->priv->box), "UnitChanged",
552 G_CALLBACK(onBoxUnitChanged), data);
553 data->priv->expand_signal =
554 g_signal_connect(G_OBJECT(data->priv->box), "notify::expansion",
555 G_CALLBACK(onBoxExtensChanged), (gpointer)data);
556 data->priv->expAct_signal =
557 g_signal_connect(G_OBJECT(data->priv->box), "notify::use-expansion",
558 G_CALLBACK(onBoxExtensActive), (gpointer)data);
559 }
560 return TRUE;
561 }
562
_inTheBox(VisuPointset * self,gboolean status)563 static gboolean _inTheBox(VisuPointset *self, gboolean status)
564 {
565 if (status)
566 _constrainedInTheBox(VISU_DATA(self), TRUE);
567 else
568 _constrainedFree(VISU_DATA(self), TRUE);
569 return TRUE;
570 }
_applyTranslation(VisuPointset * self)571 static void _applyTranslation(VisuPointset *self)
572 {
573 VisuNodeArrayIter iter;
574 float xyz[3], zeros[3] = {0.f, 0.f, 0.f};
575 gboolean rendered;
576
577 visu_node_array_iter_new(VISU_NODE_ARRAY(self), &iter);
578 for (visu_node_array_iterStart(VISU_NODE_ARRAY(self), &iter); iter.node;
579 visu_node_array_iterNext(VISU_NODE_ARRAY(self), &iter))
580 {
581 visu_data_getNodePosition(VISU_DATA(self), iter.node, xyz);
582 rendered = visu_node_getVisibility(iter.node);
583 visu_node_newValues(iter.node, xyz);
584 visu_node_setVisibility(iter.node, rendered);
585 }
586 _setTranslation(self, zeros, FALSE);
587 }
_getTranslation(VisuPointset * self,float trans[3])588 static void _getTranslation(VisuPointset *self, float trans[3])
589 {
590 VisuDataPrivate *priv;
591
592 g_return_if_fail(VISU_IS_DATA(self));
593 priv = VISU_DATA(self)->priv;
594
595 trans[0] = priv->translation[0];
596 trans[1] = priv->translation[1];
597 trans[2] = priv->translation[2];
598 }
_setTranslation(VisuPointset * self,float trans[3],gboolean withModulo)599 static gboolean _setTranslation(VisuPointset *self, float trans[3], gboolean withModulo)
600 {
601 VisuDataPrivate *priv;
602 gboolean res, changed;
603
604 g_return_val_if_fail(VISU_IS_DATA(self), FALSE);
605 priv = VISU_DATA(self)->priv;
606
607 res = FALSE;
608 if (priv->translation[0] != trans[0])
609 {
610 priv->translation[0] = trans[0];
611 res = TRUE;
612 }
613 if (priv->translation[1] != trans[1])
614 {
615 priv->translation[1] = trans[1];
616 res = TRUE;
617 }
618 if (priv->translation[2] != trans[2])
619 {
620 priv->translation[2] = trans[2];
621 res = TRUE;
622 }
623 DBG_fprintf(stderr, "Visu Data: force translation to: %f %f %f\n",
624 priv->translation[0], priv->translation[1], priv->translation[2]);
625 if (res)
626 g_object_notify(G_OBJECT(self), "translation");
627
628 changed = FALSE;
629 if (withModulo)
630 changed = _constrainedInTheBox(VISU_DATA(self), FALSE);
631
632 if ((res && priv->translationActive) || changed)
633 g_signal_emit_by_name(G_OBJECT(self), "position-changed", (GArray*)0, NULL);
634
635 return res;
636 }
_setTranslationActive(VisuPointset * self,gboolean status)637 static gboolean _setTranslationActive(VisuPointset *self, gboolean status)
638 {
639 VisuData *data;
640 gboolean changed;
641
642 g_return_val_if_fail(VISU_IS_DATA(self), FALSE);
643
644 data = VISU_DATA(self);
645 if (data->priv->translationActive == status)
646 return FALSE;
647
648 data->priv->translationActive = status;
649 g_object_notify(G_OBJECT(self), "use-translation");
650
651 changed = FALSE;
652 if (data->priv->inTheBox)
653 changed = _constrainedInTheBox(VISU_DATA(self), FALSE);
654 if (data->priv->translation[0] != 0.f ||
655 data->priv->translation[1] != 0.f ||
656 data->priv->translation[2] != 0.f ||
657 changed)
658 g_signal_emit_by_name(G_OBJECT(self), "position-changed", (GArray*)0, NULL);
659 return TRUE;
660 }
661
662 /**
663 * visu_data_getNodeBoxFromNumber:
664 * @data: a #VisuData object.
665 * @nodeId: the index of the node considered.
666 * @nodeBox: (in) (array fixed-size=3): the array to store the box of the node.
667 *
668 * This method retrieves the value of the box associated to a node (with respect to the unit cell).
669 *
670 * Returns: TRUE if everything went well, FALSE otherwise. The box is stored in the nodeBox array.
671 */
visu_data_getNodeBoxFromNumber(VisuData * data,guint nodeId,int nodeBox[3])672 gboolean visu_data_getNodeBoxFromNumber(VisuData *data, guint nodeId, int nodeBox[3])
673 {
674 float xcart[3];
675
676 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
677
678 visu_data_getNodePosition(data, visu_node_array_getFromId(VISU_NODE_ARRAY(data),nodeId), xcart);
679 visu_data_getNodeBoxFromCoord(data, xcart, nodeBox);
680 return TRUE;
681 }
682
683 /**
684 * visu_data_getNodeBoxFromCoord:
685 * @data: a #VisuData object.
686 * @xcart: (in) (array fixed-size=3): the coordinates of a node.
687 * @nodeBox: (in) (array fixed-size=3): the array to store the box of the node.
688 *
689 * This method retrieves the value of the box associated to the coordinates of the node (with respect to the unit cell).
690 *
691 * Returns: TRUE if everything went well, FALSE otherwise. The box is stored in the nodeBox array.
692 */
visu_data_getNodeBoxFromCoord(VisuData * data,float xcart[3],int nodeBox[3])693 gboolean visu_data_getNodeBoxFromCoord(VisuData *data, float xcart[3], int nodeBox[3])
694 {
695 float xred[3];
696
697 visu_box_convertXYZtoBoxCoordinates(data->priv->box, xred, xcart);
698 nodeBox[0] = floor(xred[0]);
699 nodeBox[1] = floor(xred[1]);
700 nodeBox[2] = floor(xred[2]);
701 DBG_fprintf(stderr, "Visu Data: nodeBox found for atom at %f %f %f : %d %d %d.\n",
702 xcart[0], xcart[1], xcart[2], nodeBox[0], nodeBox[1], nodeBox[2]);
703 return TRUE;
704 }
705
onBoxUnitChanged(VisuData * data,gfloat fact)706 static void onBoxUnitChanged(VisuData *data, gfloat fact)
707 {
708 VisuNodeArrayIter iter;
709
710 DBG_fprintf(stderr, "Visu Data: caught 'UnitChanged' signal with factor %g.\n", fact);
711
712 /* We do an homothety on the nodes. */
713 data->priv->translation[0] *= fact;
714 data->priv->translation[1] *= fact;
715 data->priv->translation[2] *= fact;
716 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
717 for( visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
718 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
719 {
720 iter.node->xyz[0] *= fact;
721 iter.node->xyz[1] *= fact;
722 iter.node->xyz[2] *= fact;
723 iter.node->translation[0] *= fact;
724 iter.node->translation[1] *= fact;
725 iter.node->translation[2] *= fact;
726 }
727 /* We raise the signals. */
728 g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL);
729
730 DBG_fprintf(stderr, "Visu Data: done 'UnitChanged'.\n");
731 }
onBoxExtensChanged(VisuBox * box,GParamSpec * pspec _U_,gpointer user_data)732 static void onBoxExtensChanged(VisuBox *box, GParamSpec *pspec _U_, gpointer user_data)
733 {
734 gfloat ext[3];
735
736 if (!visu_box_getExtensionActive(box))
737 return;
738
739 visu_box_getExtension(box, ext);
740 _replicate(VISU_DATA(user_data), ext);
741 }
onBoxExtensActive(VisuBox * box,GParamSpec * pspec _U_,gpointer user_data)742 static void onBoxExtensActive(VisuBox *box, GParamSpec *pspec _U_, gpointer user_data)
743 {
744 VisuData *data;
745 gfloat ext[3];
746
747 if (visu_box_getExtensionActive(box))
748 {
749 visu_box_getExtension(box, ext);
750 _replicate(VISU_DATA(user_data), ext);
751 }
752 else
753 {
754 visu_node_array_removeAllDuplicateNodes(VISU_NODE_ARRAY(user_data));
755 data = VISU_DATA(user_data);
756 data->priv->extension[0] = 0.f;
757 data->priv->extension[1] = 0.f;
758 data->priv->extension[2] = 0.f;
759 if (data->priv->inTheBox_replicate)
760 {
761 _constrainedFree(data, TRUE);
762 data->priv->inTheBox_replicate = FALSE;
763 }
764 }
765 }
766
_constrainedElementInTheBox(VisuData * data,VisuElement * element,gboolean emit)767 static gboolean _constrainedElementInTheBox(VisuData *data, VisuElement *element,
768 gboolean emit)
769 {
770 gboolean changed;
771 float cartCoord[3], t[3];
772 VisuNodeArrayIter iter;
773
774 g_return_val_if_fail(VISU_IS_DATA(data) && element, FALSE);
775
776 if (!visu_element_getRendered(element))
777 return FALSE;
778
779 DBG_fprintf(stderr, "Visu Data: Checking for nodes of element '%s'"
780 " to be in the box.\n", element->name);
781 changed = FALSE;
782 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
783 iter.element = element;
784 for(visu_node_array_iterRestartNode(VISU_NODE_ARRAY(data), &iter); iter.node;
785 visu_node_array_iterNextNode(VISU_NODE_ARRAY(data), &iter))
786 {
787 visu_data_getNodePosition(data, iter.node, cartCoord);
788 if (visu_box_constrainInside(data->priv->box, t, cartCoord, FALSE))
789 {
790 changed = TRUE;
791 iter.node->translation[0] += t[0];
792 iter.node->translation[1] += t[1];
793 iter.node->translation[2] += t[2];
794 }
795 }
796 if (changed && emit)
797 g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL);
798 return changed;
799 }
800
_constrainedInTheBox(VisuData * data,gboolean emit)801 static gboolean _constrainedInTheBox(VisuData *data, gboolean emit)
802 {
803 VisuNodeArrayIter iter;
804 gboolean changed;
805
806 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
807
808 data->priv->inTheBox = TRUE;
809 g_object_notify(G_OBJECT(data), "in-the-box");
810
811 changed = FALSE;
812 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
813 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.element;
814 visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, FALSE))
815 changed = _constrainedElementInTheBox(data, iter.element, emit) || changed;
816 return changed;
817 }
_constrainedFree(VisuData * data,gboolean emit)818 static gboolean _constrainedFree(VisuData *data, gboolean emit)
819 {
820 VisuNodeArrayIter iter;
821 gboolean moved;
822
823 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
824
825 data->priv->inTheBox = FALSE;
826 g_object_notify(G_OBJECT(data), "in-the-box");
827
828 moved = FALSE;
829 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
830 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
831 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
832 {
833 moved = moved || iter.node->translation[0] != 0. ||
834 iter.node->translation[1] != 0. ||
835 iter.node->translation[2] != 0.;
836 iter.node->translation[0] = 0.;
837 iter.node->translation[1] = 0.;
838 iter.node->translation[2] = 0.;
839 }
840 if (emit && moved)
841 g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL);
842 return TRUE;
843 }
844
845 /**
846 * visu_data_setTightBox:
847 * @data: a #VisuData object.
848 *
849 * Calculate the box geometry to have a tight box in directions that
850 * are not periodic. If some directions are still periodic, the box
851 * size in these directions should be setup first with
852 * visu_box_setGeometry().
853 *
854 * Returns: (transfer none): a new #VisuBox if @data had not one
855 * before, or the modified box of @data.
856 */
visu_data_setTightBox(VisuData * data)857 VisuBox* visu_data_setTightBox(VisuData *data)
858 {
859 double xMin, yMin, zMin, xMax, yMax, zMax, xFree, yFree, zFree;
860 double boxGeometry[6], boxGeometry_[6];
861 float xyz[3];
862 VisuNodeArrayIter iter;
863 VisuBoxBoundaries bc;
864 guint i;
865 VisuBox *box;
866
867 g_return_val_if_fail(VISU_IS_DATA(data), (VisuBox*)0);
868
869 if (!data->priv->box)
870 {
871 for (i = 0; i < VISU_BOX_N_VECTORS; i++)
872 boxGeometry_[i] = 0.;
873 box = visu_box_new(boxGeometry_, VISU_BOX_FREE);
874 visu_boxed_setBox(VISU_BOXED(data), VISU_BOXED(box));
875 g_object_unref(box);
876 }
877 bc = visu_box_getBoundary(data->priv->box);
878 if (bc == VISU_BOX_PERIODIC)
879 return data->priv->box;
880
881 /* Store the coordinates */
882 xMin = 1e5;
883 yMin = 1e5;
884 zMin = 1e5;
885 xMax = -1e5;
886 yMax = -1e5;
887 zMax = -1e5;
888 xFree = (bc & TOOL_XYZ_MASK_X)?0.:1.;
889 yFree = (bc & TOOL_XYZ_MASK_Y)?0.:1.;
890 zFree = (bc & TOOL_XYZ_MASK_Z)?0.:1.;
891
892 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
893 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
894 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
895 {
896 xMin = MIN(xMin, iter.node->xyz[0]);
897 yMin = MIN(yMin, iter.node->xyz[1]);
898 zMin = MIN(zMin, iter.node->xyz[2]);
899 xMax = MAX(xMax, iter.node->xyz[0]);
900 yMax = MAX(yMax, iter.node->xyz[1]);
901 zMax = MAX(zMax, iter.node->xyz[2]);
902 }
903
904 DBG_fprintf(stderr, "Visu Data: the elements are in [%f, %f]x[%f, %f]x[%f, %f].\n",
905 xMin, xMax, yMin, yMax, zMin, zMax);
906 for (i = 0; i < VISU_BOX_N_VECTORS; i++)
907 boxGeometry_[i] = visu_box_getGeometry(data->priv->box, i);
908 boxGeometry[0] = (xMax - xMin + 1e-5) * xFree + (1. - xFree) * boxGeometry_[0];
909 boxGeometry[1] = 0. + (1. - yFree) * boxGeometry_[1];
910 boxGeometry[2] = (yMax - yMin + 1e-5) * yFree + (1. - yFree) * boxGeometry_[2];
911 boxGeometry[3] = 0. + (1. - zFree) * boxGeometry_[3];
912 boxGeometry[4] = 0. + (1. - zFree) * boxGeometry_[4];
913 boxGeometry[5] = (zMax - zMin + 1e-5) * zFree + (1. - zFree) * boxGeometry_[5];
914 visu_box_setGeometry(data->priv->box, boxGeometry);
915
916 xyz[0] = -xMin * xFree;
917 xyz[1] = -yMin * yFree;
918 xyz[2] = -zMin * zFree;
919 visu_pointset_setTranslation(VISU_POINTSET(data), xyz, FALSE);
920 visu_pointset_setTranslationActive(VISU_POINTSET(data), TRUE);
921
922 return data->priv->box;
923 }
924
_replicate(VisuData * data,gfloat extension[3])925 static void _replicate(VisuData *data, gfloat extension[3])
926 {
927 int i;
928 GArray *index;
929
930 g_return_if_fail(VISU_IS_DATA(data));
931 g_return_if_fail(extension[0] >= 0. &&
932 extension[1] >= 0. &&
933 extension[2] >= 0.);
934
935 DBG_fprintf(stderr, "Visu Data: modify extension from (%g, %g, %g).\n",
936 data->priv->extension[0], data->priv->extension[1], data->priv->extension[2]);
937 if (!data->priv->inTheBox)
938 {
939 _constrainedInTheBox(data, TRUE);
940 data->priv->inTheBox_replicate = TRUE;
941 }
942
943 /* Keep only three digits for the extension to avoid rounding
944 troubles. */
945 extension[0] = (float)((int)(extension[0] * 1000)) / 1000;
946 extension[1] = (float)((int)(extension[1] * 1000)) / 1000;
947 extension[2] = (float)((int)(extension[2] * 1000)) / 1000;
948
949 for (i = 0; i < 3; i++)
950 {
951 if (data->priv->extension[i] > extension[i])
952 {
953 index = shrinkNodeList(data, i, extension[i]);
954 if (index->len > 0)
955 visu_node_array_removeNodes(VISU_NODE_ARRAY(data), index);
956 g_array_unref(index);
957 }
958 else if (data->priv->extension[i] < extension[i])
959 extendNodeList(data, i, data->priv->extension[i], extension[i]);
960 data->priv->extension[i] = extension[i];
961 }
962 g_object_notify(G_OBJECT(data), "n-nodes");
963 if (DEBUG)
964 visu_node_array_traceProperty(VISU_NODE_ARRAY(data), "originalId");
965 }
966
shrinkNodeList(VisuData * data,int coord,float valueTo)967 static GArray* shrinkNodeList(VisuData *data, int coord, float valueTo)
968 {
969 float cartCoord[3], boxCoord[3];
970 GArray *index;
971 VisuNodeArrayIter iter;
972
973 g_return_val_if_fail(coord == 0 || coord == 1 || coord == 2, FALSE);
974 g_return_val_if_fail(valueTo >= 0.f, FALSE);
975
976 DBG_fprintf(stderr, "Visu Data: shrink to %g (%d).\n", valueTo, coord);
977 index = g_array_new(FALSE, FALSE, sizeof(guint));
978 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
979 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
980 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
981 {
982 visu_data_getNodePosition(data, iter.node, cartCoord);
983 visu_box_convertXYZtoBoxCoordinates(data->priv->box, boxCoord, cartCoord);
984 if ((boxCoord[coord] < - valueTo - 1e-6 || /* We are out on the
985 low coord. */
986 boxCoord[coord] >= 1.f + valueTo -1e-6) && /* We are out on
987 the high
988 coord. */
989 visu_node_array_getOriginal(VISU_NODE_ARRAY(data), iter.node->number) >= 0)
990 /* We remove the element. */
991 g_array_append_val(index, iter.node->number);
992 DBG_fprintf(stderr, "Visu Data: test shrink for %d: %d %15.12fx%15.12fx%15.12f.\n",
993 iter.node->number, index->len, boxCoord[0], boxCoord[1], boxCoord[2]);
994 }
995 return index;
996 }
extendNodeList(VisuData * data,int coord,float valueFrom,float valueTo)997 static void extendNodeList(VisuData *data, int coord, float valueFrom, float valueTo)
998 {
999 int k, id;
1000 unsigned nb, nbInit;
1001 VisuNode *newNode;
1002 float cartCoord[3], boxCoord[3], ratio;
1003 VisuNodeArrayIter iter;
1004 VisuBoxBoundaries bc;
1005
1006 g_return_if_fail(coord == 0 || coord == 1 || coord == 2);
1007 g_return_if_fail(valueTo > valueFrom);
1008
1009 DBG_fprintf(stderr, "Visu Data: expand in %d direction to %g.\n",
1010 coord, valueTo);
1011 DBG_fprintf(stderr, " | k runs in [%d %d[ ]%d %d].\n", (int)floor(-valueTo),
1012 -(int)valueFrom, (int)valueFrom, (int)ceil(valueTo));
1013 DBG_fprintf(stderr, " | keeps new ele in [%g %g] [%g %g].\n", -valueTo,
1014 -valueFrom, valueFrom + 1.f, valueTo + 1.f);
1015
1016 /* We estimate the number of data to be added and we call a realloc of
1017 this amount now to avoid to much small reallocations.
1018 The slab of box to be extend is 2*(valueTo-extension[coord]).
1019 So the volume in box coordinates is the same value and since
1020 the volume in box coordinates is product(1+2*extension),
1021 the ratio of new space is the fraction.
1022 So we realloc all elements on this ratio. */
1023 ratio = (2.f * (valueTo - valueFrom)) / (1.f + 2.f * valueFrom);
1024 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
1025 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.element;
1026 visu_node_array_iterNextElement(VISU_NODE_ARRAY(data), &iter, FALSE))
1027 {
1028 nb = (int)ceil((float)iter.nStoredNodes * ratio);
1029 visu_node_array_allocateNodesForElement(VISU_NODE_ARRAY(data), iter.iElement,
1030 iter.nStoredNodes + nb);
1031 }
1032
1033 bc = visu_box_getBoundary(data->priv->box);
1034
1035 /* All node with an id higher than nbInit are considered as new
1036 nodes. */
1037 nbInit = G_MAXUINT;
1038 visu_node_array_startAdding(VISU_NODE_ARRAY(data));
1039 for (visu_node_array_iterStartNumber(VISU_NODE_ARRAY(data), &iter); iter.node;
1040 visu_node_array_iterNextNodeNumber(VISU_NODE_ARRAY(data), &iter))
1041 {
1042 /* Do not duplicate the new nodes. */
1043 if (iter.node->number > nbInit)
1044 continue;
1045 visu_data_getNodePosition(data, iter.node, cartCoord);
1046 visu_box_convertXYZtoBoxCoordinates(data->priv->box, boxCoord, cartCoord);
1047 for (k = (int)floor(-valueTo); k < (int)ceil(valueTo) + 1; k++)
1048 {
1049 if (k >= -(int)valueFrom && k < (int)valueFrom + 1)
1050 continue;
1051 boxCoord[coord] += (float)k;
1052 if ((boxCoord[coord] >= -valueTo && boxCoord[coord] < -valueFrom ) ||
1053 (boxCoord[coord] < valueTo + 1.f && boxCoord[coord] >= valueFrom + 1.f))
1054 {
1055 DBG_fprintf(stderr, "Visu Data: replicating node %d, (%d)"
1056 " (%15.12fx%15.12fx%15.12f).\n", iter.node->number, coord,
1057 boxCoord[0], boxCoord[1], boxCoord[2]);
1058 /* We save the current node id, because the pointer may be
1059 relocated by the visu_node_array_copyNode() call. */
1060 id = iter.node->number;
1061 /* We create and add a new element. */
1062 newNode = visu_node_array_copyNode(VISU_NODE_ARRAY(data), iter.node);
1063 if (nbInit == G_MAXUINT)
1064 nbInit = newNode->number - 1;
1065 visu_box_convertBoxCoordinatestoXYZ(data->priv->box,
1066 newNode->xyz, boxCoord);
1067 if (!(bc & TOOL_XYZ_MASK_X) || data->priv->translationActive)
1068 newNode->xyz[0] -= data->priv->translation[0];
1069 if (!(bc & TOOL_XYZ_MASK_Y) || data->priv->translationActive)
1070 newNode->xyz[1] -= data->priv->translation[1];
1071 if (!(bc & TOOL_XYZ_MASK_Z) || data->priv->translationActive)
1072 newNode->xyz[2] -= data->priv->translation[2];
1073 if (data->priv->inTheBox)
1074 {
1075 newNode->xyz[0] -= newNode->translation[0];
1076 newNode->xyz[1] -= newNode->translation[1];
1077 newNode->xyz[2] -= newNode->translation[2];
1078 }
1079 /* We reset the iter.node pointer. */
1080 iter.node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), id);
1081 }
1082 boxCoord[coord] -= (float)k;
1083 }
1084 }
1085 visu_node_array_completeAdding(VISU_NODE_ARRAY(data));
1086 }
1087
1088 /**
1089 * visu_data_getAllNodeExtens:
1090 * @dataObj: a #VisuData object.
1091 * @box: (allow-none): a #VisuBox object.
1092 *
1093 * Calculate the longest distance between the surface of @box (without
1094 * extension) and all the nodes. If @box is NULL, then the internal
1095 * box of @dataObj is used.
1096 *
1097 * Since: 3.7
1098 *
1099 * Returns: the longest distance between the surface of @box (without
1100 * extension) and all the nodes.
1101 **/
visu_data_getAllNodeExtens(VisuData * dataObj,VisuBox * box)1102 gfloat visu_data_getAllNodeExtens(VisuData *dataObj, VisuBox *box)
1103 {
1104 VisuNodeArrayIter iter;
1105 float xyz[2][3], t[3], lg[2], coord[3];
1106
1107 g_return_val_if_fail(VISU_IS_DATA(dataObj), 0.f);
1108
1109 if (!box)
1110 box = dataObj->priv->box;
1111
1112 t[0] = (float)(visu_box_getGeometry(box, VISU_BOX_DXX) +
1113 visu_box_getGeometry(box, VISU_BOX_DYX) +
1114 visu_box_getGeometry(box, VISU_BOX_DZX));
1115 t[1] = (float)(visu_box_getGeometry(box, VISU_BOX_DYY) +
1116 visu_box_getGeometry(box, VISU_BOX_DZY));
1117 t[2] = (float)(visu_box_getGeometry(box, VISU_BOX_DZZ));
1118 xyz[0][0] = xyz[0][1] = xyz[0][2] = 0.f;
1119 xyz[1][0] = xyz[1][1] = xyz[1][2] = 0.f;
1120
1121 visu_node_array_iter_new(VISU_NODE_ARRAY(dataObj), &iter);
1122 for (visu_node_array_iterStart(VISU_NODE_ARRAY(dataObj), &iter); iter.node;
1123 visu_node_array_iterNext(VISU_NODE_ARRAY(dataObj), &iter))
1124 {
1125 visu_data_getNodePosition(dataObj, iter.node, coord);
1126 xyz[0][0] = MIN(xyz[0][0], coord[0]);
1127 xyz[0][1] = MIN(xyz[0][1], coord[1]);
1128 xyz[0][2] = MIN(xyz[0][2], coord[2]);
1129
1130 xyz[1][0] = MAX(xyz[1][0], coord[0]);
1131 xyz[1][1] = MAX(xyz[1][1], coord[1]);
1132 xyz[1][2] = MAX(xyz[1][2], coord[2]);
1133 }
1134 xyz[1][0] -= t[0];
1135 xyz[1][1] -= t[1];
1136 xyz[1][2] -= t[2];
1137 /* Compute the longest vector out of the box. */
1138 lg[0] = sqrt(xyz[0][0] * xyz[0][0] +
1139 xyz[0][1] * xyz[0][1] +
1140 xyz[0][2] * xyz[0][2]);
1141 lg[1] = sqrt(xyz[1][0] * xyz[1][0] +
1142 xyz[1][1] * xyz[1][1] +
1143 xyz[1][2] * xyz[1][2]);
1144 DBG_fprintf(stderr, "VisuData: vectors outside of the box %g %g.\n", lg[0], lg[1]);
1145 return MAX(lg[0], lg[1]);
1146 }
1147
1148 /**
1149 * visu_data_setNewBasisFromNodes:
1150 * @data: a #VisuData object.
1151 * @nO: the index of node as origin.
1152 * @nA: the index of node on X axis.
1153 * @nB: the index of node as Y axis.
1154 * @nC: the index of node as Z axis.
1155 *
1156 * Change the basis set by providing the new basis set from a list of
1157 * nodes. See also visu_data_setNewBasis(). Nodes outside the new box
1158 * are killed.
1159 *
1160 * Since: 3.6
1161 *
1162 * Returns: TRUE if the new basis set is valid.
1163 */
visu_data_setNewBasisFromNodes(VisuData * data,guint nO,guint nA,guint nB,guint nC)1164 gboolean visu_data_setNewBasisFromNodes(VisuData *data, guint nO, guint nA, guint nB, guint nC)
1165 {
1166 VisuNode *orig, *nodeA, *nodeB, *nodeC;
1167 float matA[3][3], O[3], xyz[3];
1168
1169 orig = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nO);
1170 DBG_fprintf(stderr, " orig = %p\n", (gpointer)orig);
1171 nodeA = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nA);
1172 DBG_fprintf(stderr, " nodeA = %p\n", (gpointer)nodeA);
1173 nodeB = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nB);
1174 DBG_fprintf(stderr, " nodeB = %p\n", (gpointer)nodeB);
1175 nodeC = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nC);
1176 DBG_fprintf(stderr, " nodeC = %p\n", (gpointer)nodeC);
1177 g_return_val_if_fail(orig && nodeA && nodeB && nodeC, FALSE);
1178
1179 visu_data_getNodePosition(data, orig, O);
1180 visu_data_getNodePosition(data, nodeA, xyz);
1181 matA[0][0] = xyz[0] - O[0];
1182 matA[1][0] = xyz[1] - O[1];
1183 matA[2][0] = xyz[2] - O[2];
1184 visu_data_getNodePosition(data, nodeB, xyz);
1185 matA[0][1] = xyz[0] - O[0];
1186 matA[1][1] = xyz[1] - O[1];
1187 matA[2][1] = xyz[2] - O[2];
1188 visu_data_getNodePosition(data, nodeC, xyz);
1189 matA[0][2] = xyz[0] - O[0];
1190 matA[1][2] = xyz[1] - O[1];
1191 matA[2][2] = xyz[2] - O[2];
1192
1193 return visu_data_setNewBasis(data, matA, O);
1194 }
1195 /**
1196 * visu_data_setNewBasis:
1197 * @data: a #VisuData object.
1198 * @matA: a basis set definition.
1199 * @O: the origin cartesian coordinates.
1200 *
1201 * Change the basis set of @data according to the new definition given
1202 * by @matA and @O. Nodes outside the new box are killed. See also
1203 * visu_data_setNewBasisFromNodes() for a convenient function using
1204 * nodes as basis set definition.
1205 *
1206 * Since: 3.6
1207 *
1208 * Returns: TRUE if the new basis set is valid.
1209 */
visu_data_setNewBasis(VisuData * data,float matA[3][3],float O[3])1210 gboolean visu_data_setNewBasis(VisuData *data, float matA[3][3], float O[3])
1211 {
1212 double mat_[3][3];
1213 float inv[3][3], vect[3], xred[3];
1214 double box[6];
1215 float vectEps[3], deltaEps[3];
1216 VisuNodeArrayIter iter;
1217 GArray *rmNodes;
1218 float zeros[3] = {0.f, 0.f, 0.f};
1219 #define EPS 1.e-5
1220
1221 DBG_fprintf(stderr, "Visu Data: basis matrice:\n");
1222 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1223 matA[0][0], matA[0][1], matA[0][2]);
1224 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1225 matA[1][0], matA[1][1], matA[1][2]);
1226 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1227 matA[2][0], matA[2][1], matA[2][2]);
1228 if (!tool_matrix_invert(inv, matA))
1229 return FALSE;
1230 DBG_fprintf(stderr, "Visu Data: transformation matrice:\n");
1231 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1232 inv[0][0], inv[0][1], inv[0][2]);
1233 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1234 inv[1][0], inv[1][1], inv[1][2]);
1235 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1236 inv[2][0], inv[2][1], inv[2][2]);
1237
1238 mat_[0][0] = (double)matA[0][0];
1239 mat_[1][0] = (double)matA[0][1];
1240 mat_[2][0] = (double)matA[0][2];
1241 mat_[0][1] = (double)matA[1][0];
1242 mat_[1][1] = (double)matA[1][1];
1243 mat_[2][1] = (double)matA[1][2];
1244 mat_[0][2] = (double)matA[2][0];
1245 mat_[1][2] = (double)matA[2][1];
1246 mat_[2][2] = (double)matA[2][2];
1247 if (!tool_matrix_reducePrimitiveVectors(box, mat_))
1248 return FALSE;
1249 DBG_fprintf(stderr, "Visu Data: new box:\n");
1250 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1251 box[0], box[1], box[2]);
1252 DBG_fprintf(stderr, " (%10.5f %10.5f %10.5f)\n",
1253 box[3], box[4], box[5]);
1254
1255 visu_box_setBoundary(data->priv->box, VISU_BOX_PERIODIC);
1256 /* Trick to avoid the emission of SizeChanged signal. */
1257 visu_box_setMargin(data->priv->box, G_MAXFLOAT, FALSE);
1258 visu_box_setGeometry(data->priv->box, box);
1259 /* Remove possible extension. */
1260 g_signal_handler_block(G_OBJECT(data->priv->box), data->priv->expand_signal);
1261 visu_box_setExtension(data->priv->box, zeros);
1262 g_signal_handler_unblock(G_OBJECT(data->priv->box), data->priv->expand_signal);
1263
1264 /* We need to move all the atoms of (eps, eps, eps) in the new box
1265 to avoid rounding problems. */
1266 xred[0] = 1.f;
1267 xred[1] = 1.f;
1268 xred[2] = 1.f;
1269 tool_matrix_productVector(vect, matA, xred);
1270 vectEps[0] = (vect[0] >= 0.f)?EPS:-EPS;
1271 vectEps[1] = (vect[1] >= 0.f)?EPS:-EPS;
1272 vectEps[2] = (vect[2] >= 0.f)?EPS:-EPS;
1273 tool_matrix_productVector(xred, inv, vectEps);
1274 visu_box_convertBoxCoordinatestoXYZ(data->priv->box, deltaEps, xred);
1275 DBG_fprintf(stderr, "Visu Data: applied epsilon (%10.5f %10.5f %10.5f)\n",
1276 vectEps[0], vectEps[1], vectEps[2]);
1277
1278 /* Transform each atomic coordinates using this matrice. */
1279 DBG_fprintf(stderr, "Visu Data: reset the coordinates for all nodes.\n");
1280 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
1281 rmNodes = g_array_new(FALSE, FALSE, sizeof(guint));
1282 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
1283 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
1284 {
1285 visu_data_getNodePosition(data, iter.node, vect);
1286 vect[0] += - O[0] + vectEps[0];
1287 vect[1] += - O[1] + vectEps[1];
1288 vect[2] += - O[2] + vectEps[2];
1289 tool_matrix_productVector(xred, inv, vect);
1290 if (xred[0] < 0.f || xred[0] >= 1.f ||
1291 xred[1] < 0.f || xred[1] >= 1.f ||
1292 xred[2] < 0.f || xred[2] >= 1.f)
1293 {
1294 g_array_append_val(rmNodes, iter.node->number);
1295 DBG_fprintf(stderr, " | %d (%6.1f %6.1f %6.1f)"
1296 " %10.5f %10.5f %10.5f -> removed\n",
1297 iter.node->number, vect[0], vect[1], vect[2],
1298 xred[0], xred[1], xred[2]);
1299 }
1300 else
1301 {
1302 visu_box_convertBoxCoordinatestoXYZ(data->priv->box, iter.node->xyz, xred);
1303 iter.node->xyz[0] -= deltaEps[0];
1304 iter.node->xyz[1] -= deltaEps[1];
1305 iter.node->xyz[2] -= deltaEps[2];
1306 iter.node->translation[0] = 0.f;
1307 iter.node->translation[1] = 0.f;
1308 iter.node->translation[2] = 0.f;
1309 visu_node_array_setOriginal(VISU_NODE_ARRAY(data), iter.node->number);
1310 DBG_fprintf(stderr, " | %d (%6.1f %6.1f %6.1f)"
1311 " %10.5f %10.5f %10.5f -> %10.5f %10.5f %10.5f\n",
1312 iter.node->number, vect[0], vect[1], vect[2],
1313 xred[0], xred[1], xred[2], iter.node->xyz[0],
1314 iter.node->xyz[1], iter.node->xyz[2]);
1315 }
1316 }
1317
1318 visu_node_array_removeNodes(VISU_NODE_ARRAY(data), rmNodes);
1319 g_array_free(rmNodes, TRUE);
1320
1321 /* Remove possible translation. */
1322 visu_pointset_setTranslation(VISU_POINTSET(data), zeros, FALSE);
1323 visu_pointset_setTranslationActive(VISU_POINTSET(data), FALSE);
1324 visu_pointset_setInTheBox(VISU_POINTSET(data), FALSE);
1325 g_signal_emit_by_name(G_OBJECT(data), "position-changed", (GArray*)0, NULL);
1326
1327 return TRUE;
1328 }
1329 /**
1330 * visu_data_reorder:
1331 * @data: a #VisuData object, to reorder.
1332 * @dataRef: a #VisuData object, to take the order from.
1333 *
1334 * This routine modifies the node ordering of @data using the order in
1335 * @dataRef. The association is done by nearest neigbours conditions.
1336 *
1337 * Since: 3.6
1338 *
1339 * Returns: TRUE is the reordering is successfull (i.e. all nodes of
1340 * @data correspond to one of @dataRef).
1341 */
visu_data_reorder(VisuData * data,const VisuData * dataRef)1342 gboolean visu_data_reorder(VisuData *data, const VisuData *dataRef)
1343 {
1344 VisuNodeArrayIter iter, iterRef;
1345 float d, diff[3], xyz[3], dMin;
1346 guint id;
1347
1348 g_return_val_if_fail(VISU_IS_DATA(dataRef), FALSE);
1349 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
1350
1351 DBG_fprintf(stderr, "Geometry: reorder between %p and %p.\n",
1352 (gpointer)dataRef, (gpointer)data);
1353
1354 DBG_fprintf(stderr, " | %d - %d.\n", visu_node_array_getNNodes(VISU_NODE_ARRAY(data)),
1355 visu_node_array_getNNodes(VISU_NODE_ARRAY_CONST(dataRef)));
1356 if (visu_node_array_getNNodes(VISU_NODE_ARRAY(data)) !=
1357 visu_node_array_getNNodes(VISU_NODE_ARRAY_CONST(dataRef)))
1358 return FALSE;
1359
1360 visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
1361 for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
1362 visu_node_array_iterNext(VISU_NODE_ARRAY(data), &iter))
1363 {
1364 id = 0;
1365 dMin = G_MAXFLOAT;
1366 visu_data_getNodePosition(data, iter.node, xyz);
1367 visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef);
1368 iterRef.element = iter.element;
1369 for (visu_node_array_iterRestartNode(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef); iterRef.node;
1370 visu_node_array_iterNextNode(VISU_NODE_ARRAY((VisuNodeArray*)dataRef), &iterRef))
1371 {
1372 visu_data_getNodePosition(dataRef, iterRef.node, diff);
1373 diff[0] -= xyz[0];
1374 diff[1] -= xyz[1];
1375 diff[2] -= xyz[2];
1376 visu_box_getPeriodicVector(visu_boxed_getBox(VISU_BOXED(data)), diff);
1377 d = diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2];
1378 if (d < dMin)
1379 {
1380 id = iterRef.node->number;
1381 dMin = d;
1382 }
1383 }
1384 DBG_fprintf(stderr, " | %d %d -> %g\n", iter.node->number, id, dMin);
1385 visu_node_array_switchNumber(VISU_NODE_ARRAY(data), iter.node->number, id);
1386 }
1387 return TRUE;
1388 }
1389
1390
1391 /*****************************/
1392 /* The node related routines */
1393 /*****************************/
_addNode(VisuData * data,VisuNode * node,float xyz[3],gboolean reduced)1394 static VisuNode* _addNode(VisuData *data, VisuNode *node,
1395 float xyz[3], gboolean reduced)
1396 {
1397 float coord[3];
1398
1399 g_return_val_if_fail(VISU_IS_DATA(data) && node, (VisuNode*)0);
1400 /* If coordinates are reduced, we expand them. */
1401 DBG_fprintf(stderr, "Visu Data: set node coordinates from (%g;%g;%g).\n",
1402 xyz[0], xyz[1], xyz[2]);
1403 if (reduced)
1404 visu_box_convertBoxCoordinatestoXYZ(data->priv->box, coord, xyz);
1405 else
1406 {
1407 coord[0] = xyz[0];
1408 coord[1] = xyz[1];
1409 coord[2] = xyz[2];
1410 }
1411
1412 visu_node_newValues(node, coord);
1413
1414 return node;
1415 }
1416
1417 /**
1418 * visu_data_addNodeFromIndex:
1419 * @data: the #VisuData where to add the new #VisuNode ;
1420 * @position: a integer corresponding to the position of
1421 * a #VisuElement in the array **nodes in the structure;
1422 * @xyz: (in) (array fixed-size=3): its coordinates ;
1423 * @reduced: coordinates are in reduced coordinates ;
1424 *
1425 * This method adds a new #VisuNode to the specified #VisuData. Position must be
1426 * chosen between 0 and (ntype - 1) and corresponds to the position of the array
1427 * in #VisuNodeArray of a #VisuElement. If several node should be added in
1428 * a row, consider using visu_node_array_startAdding() and
1429 * visu_node_array_completeAdding().
1430 *
1431 * Returns: (transfer none): a pointer to the newly created node.
1432 */
visu_data_addNodeFromIndex(VisuData * data,guint position,float xyz[3],gboolean reduced)1433 VisuNode* visu_data_addNodeFromIndex(VisuData *data, guint position,
1434 float xyz[3], gboolean reduced)
1435 {
1436 return _addNode(data, visu_node_array_getNewNodeForId(VISU_NODE_ARRAY(data),
1437 position), xyz, reduced);
1438 }
1439
1440 /**
1441 * visu_data_addNodeFromElement:
1442 * @data: the #VisuData where to add the new #VisuNode ;
1443 * @ele: the #VisuElement kind of the new #VisuNode ;
1444 * @xyz: (in) (array fixed-size=3): its coordinates ;
1445 * @reduced: coordinates are in reduced coordinates ;
1446 *
1447 * This method adds a new #VisuNode to the specified #VisuData. If
1448 * several node should be added in a row, consider using
1449 * visu_node_array_startAdding() and
1450 * visu_node_array_completeAdding().
1451 *
1452 * Returns: (transfer none): a pointer to the newly created node.
1453 */
visu_data_addNodeFromElement(VisuData * data,VisuElement * ele,float xyz[3],gboolean reduced)1454 VisuNode* visu_data_addNodeFromElement(VisuData *data, VisuElement *ele,
1455 float xyz[3], gboolean reduced)
1456 {
1457 return _addNode(data, visu_node_array_getNewNode(VISU_NODE_ARRAY(data),
1458 ele), xyz, reduced);
1459 }
1460 /**
1461 * visu_data_addNodeFromElementName:
1462 * @data: the #VisuData where to add the new #VisuNode ;
1463 * @name: the name of the element ;
1464 * @xyz: (in) (array fixed-size=3): its coordinates ;
1465 * @reduced: coordinates are in reduced coordinates ;
1466 *
1467 * This method adds a new #VisuNode to the specified #VisuData. If
1468 * several node should be added in a row, consider using
1469 * visu_node_array_startAdding() and
1470 * visu_node_array_completeAdding().
1471 *
1472 * Returns: (transfer none): a pointer to the newly created node.
1473 *
1474 * Since: 3.6
1475 */
visu_data_addNodeFromElementName(VisuData * data,const gchar * name,float xyz[3],gboolean reduced)1476 VisuNode* visu_data_addNodeFromElementName(VisuData *data, const gchar *name,
1477 float xyz[3], gboolean reduced)
1478 {
1479 return visu_data_addNodeFromElement(data, visu_element_retrieveFromName(name, (gboolean*)0), xyz, reduced);
1480 }
1481
1482 /**
1483 * visu_data_getNodeCoordinates:
1484 * @data: a #VisuData object ;
1485 * @node: a #VisuNode object ;
1486 * @user: a boolean.
1487 * @x: (out caller-allocates): the x coordinate.
1488 * @y: (out caller-allocates): the y coordinate.
1489 * @z: (out caller-allocates): the z coordinate.
1490 *
1491 * Wrapper for the function visu_data_getNodePosition() in case of call
1492 * from python. If @user is TRUE, it wraps
1493 * visu_data_getNodeUserPosition() instead.
1494 *
1495 * Since: 3.6
1496 */
visu_data_getNodeCoordinates(VisuData * data,VisuNode * node,gboolean user,float * x,float * y,float * z)1497 void visu_data_getNodeCoordinates(VisuData *data, VisuNode *node, gboolean user,
1498 float *x, float *y, float *z)
1499 {
1500 float xyz[3];
1501
1502 g_return_if_fail(x && y && z);
1503
1504 if (user)
1505 visu_data_getNodeUserPosition(data, node, xyz);
1506 else
1507 visu_data_getNodePosition(data, node, xyz);
1508 *x = xyz[0];
1509 *y = xyz[1];
1510 *z = xyz[2];
1511 }
1512 /**
1513 * visu_data_getNodePosition: (skip)
1514 * @data: a #VisuData object ;
1515 * @node: a #VisuNode object ;
1516 * @coord: (array fixed-size=3) (out caller-allocates): an array of 3
1517 * floating point values to store the position.
1518 *
1519 * Position of nodes are subject to various translations and different transformations.
1520 * Their coordinates should not be access directly through node.[xyz]. This method
1521 * is used to retrieve the given node position.
1522 *
1523 */
visu_data_getNodePosition(const VisuData * data,const VisuNode * node,float coord[3])1524 void visu_data_getNodePosition(const VisuData *data, const VisuNode *node, float coord[3])
1525 {
1526 VisuBoxBoundaries bc;
1527
1528 g_return_if_fail(VISU_IS_DATA(data) && node && coord);
1529
1530 coord[0] = node->xyz[0];
1531 coord[1] = node->xyz[1];
1532 coord[2] = node->xyz[2];
1533 bc = (data->priv->box) ? visu_box_getBoundary(data->priv->box) : VISU_BOX_PERIODIC;
1534 if (!(bc & TOOL_XYZ_MASK_X) || data->priv->translationActive)
1535 coord[0] += data->priv->translation[0];
1536 if (!(bc & TOOL_XYZ_MASK_Y) || data->priv->translationActive)
1537 coord[1] += data->priv->translation[1];
1538 if (!(bc & TOOL_XYZ_MASK_Z) || data->priv->translationActive)
1539 coord[2] += data->priv->translation[2];
1540 if (data->priv->inTheBox)
1541 {
1542 coord[0] += node->translation[0];
1543 coord[1] += node->translation[1];
1544 coord[2] += node->translation[2];
1545 }
1546 }
1547 /**
1548 * visu_data_getNodeUserPosition: (skip)
1549 * @data: a #VisuData object ;
1550 * @node: a #VisuNode object ;
1551 * @coord: (array fixed-size=3) (out caller-allocates): an array of 3
1552 * floating point values to store the position.
1553 *
1554 * This routine is equivalent to visu_data_getNodePosition() except
1555 * that it's not applying internal box translation for non periodic
1556 * directions.
1557 *
1558 * Since: 3.7
1559 */
visu_data_getNodeUserPosition(const VisuData * data,const VisuNode * node,float coord[3])1560 void visu_data_getNodeUserPosition(const VisuData *data, const VisuNode *node, float coord[3])
1561 {
1562 VisuBoxBoundaries bc;
1563
1564 g_return_if_fail(VISU_IS_DATA(data) && node && coord);
1565
1566 visu_data_getNodePosition(data, node, coord);
1567 bc = visu_box_getBoundary(data->priv->box);
1568 if (!(bc & TOOL_XYZ_MASK_X))
1569 coord[0] -= data->priv->translation[0];
1570 if (!(bc & TOOL_XYZ_MASK_Y))
1571 coord[1] -= data->priv->translation[1];
1572 if (!(bc & TOOL_XYZ_MASK_Z))
1573 coord[2] -= data->priv->translation[2];
1574 }
1575
1576
1577 /*****************/
1578 /* Miscellaneous */
1579 /*****************/
1580 /**
1581 * visu_data_addNodeProperties:
1582 * @data: a #VisuData object.
1583 * @values: (transfer full): a #VisuNodeValues object.
1584 *
1585 * Add @values as a known #VisuNodeValues property of @data.
1586 *
1587 * Since: 3.8
1588 *
1589 * Returns: TRUE if @values is added as a valid node property of @data.
1590 **/
visu_data_addNodeProperties(VisuData * data,VisuNodeValues * values)1591 gboolean visu_data_addNodeProperties(VisuData *data, VisuNodeValues *values)
1592 {
1593 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
1594 g_return_val_if_fail(visu_node_values_fromArray(values, VISU_NODE_ARRAY(data)), FALSE);
1595
1596 if (g_hash_table_contains(data->priv->nodeProperties,
1597 visu_node_values_getLabel(values)))
1598 return FALSE;
1599
1600 g_hash_table_insert(data->priv->nodeProperties,
1601 (gpointer)visu_node_values_getLabel(values),
1602 values);
1603 g_signal_emit(data, visu_data_signals[NODE_PROP_ADDED_SIGNAL], 0, values);
1604
1605 return TRUE;
1606 }
1607 /**
1608 * visu_data_removeNodeProperties:
1609 * @data: a #VisuData object.
1610 * @label: a string.
1611 *
1612 * Look for a #VisuNodeValues object labelled by @label and remove it.
1613 *
1614 * Since: 3.8
1615 *
1616 * Returns: TRUE if @label was indeed attached to @data.
1617 **/
visu_data_removeNodeProperties(VisuData * data,const gchar * label)1618 gboolean visu_data_removeNodeProperties(VisuData *data, const gchar *label)
1619 {
1620 VisuNodeValues *values;
1621
1622 g_return_val_if_fail(VISU_IS_DATA(data), FALSE);
1623
1624 values = g_hash_table_lookup(data->priv->nodeProperties, label);
1625 if (!values)
1626 return FALSE;
1627
1628 g_object_ref(values);
1629 g_hash_table_remove(data->priv->nodeProperties, label);
1630 g_signal_emit(data, visu_data_signals[NODE_PROP_REMOVED_SIGNAL], 0, values);
1631 g_object_unref(values);
1632
1633 return TRUE;
1634 }
_sortProperties(const VisuNodeValues * propA,const VisuNodeValues * propB)1635 static gint _sortProperties(const VisuNodeValues *propA, const VisuNodeValues *propB)
1636 {
1637 if (VISU_IS_NODE_VALUES_ID(propA))
1638 return -1;
1639 else if (VISU_IS_NODE_VALUES_ID(propB))
1640 return +1;
1641 else if (VISU_IS_NODE_VALUES(propA))
1642 return -1;
1643 else if (VISU_IS_NODE_VALUES(propB))
1644 return +1;
1645 else if (VISU_IS_NODE_VALUES_COORD(propA))
1646 return -1;
1647 else if (VISU_IS_NODE_VALUES_COORD(propB))
1648 return +1;
1649 else
1650 return g_strcmp0(visu_node_values_getLabel(propA),
1651 visu_node_values_getLabel(propB));
1652 }
1653 /**
1654 * visu_data_getAllNodeProperties:
1655 * @data: a #VisuData object.
1656 *
1657 * Retrieve all the #VisuNodeValues objects attached to @data
1658 * formatted as a list.
1659 *
1660 * Since: 3.8
1661 *
1662 * Returns: (transfer container) (element-type VisuNodeValues): a
1663 * newly created list of #VisuNodeValues objects.
1664 **/
visu_data_getAllNodeProperties(VisuData * data)1665 GList* visu_data_getAllNodeProperties(VisuData *data)
1666 {
1667 g_return_val_if_fail(VISU_IS_DATA(data), (GList*)0);
1668
1669 return g_list_sort(g_hash_table_get_values(data->priv->nodeProperties),
1670 (GCompareFunc)_sortProperties);
1671 }
1672 /**
1673 * visu_data_getNodeProperties:
1674 * @data: a #VisuData object.
1675 * @label: a string.
1676 *
1677 * Look for the #VisuNodeValues labelled by @label.
1678 *
1679 * Since: 3.8
1680 *
1681 * Returns: (transfer none): the #VisuNodeValues object attached to
1682 * @data with @label, if any.
1683 **/
visu_data_getNodeProperties(VisuData * data,const gchar * label)1684 VisuNodeValues* visu_data_getNodeProperties(VisuData *data, const gchar *label)
1685 {
1686 g_return_val_if_fail(VISU_IS_DATA(data), (VisuNodeValues*)0);
1687
1688 return g_hash_table_lookup(data->priv->nodeProperties, label);
1689 }
1690 #define DATA_LABEL_ID _("Label")
1691 /**
1692 * visu_data_getNodeLabels:
1693 * @data: a #VisuData object.
1694 *
1695 * Retrieve the #VisuNodeValuesString object that is used to store
1696 * labels, creating it if necessary.
1697 *
1698 * Since: 3.8
1699 *
1700 * Returns: (transfer none): the #VisuNodeValuesString object used to
1701 * store labels.
1702 **/
visu_data_getNodeLabels(VisuData * data)1703 VisuNodeValuesString* visu_data_getNodeLabels(VisuData *data)
1704 {
1705 VisuNodeValues *vals;
1706
1707 vals = visu_data_getNodeProperties(data, DATA_LABEL_ID);
1708 if (!vals)
1709 {
1710 vals = VISU_NODE_VALUES(visu_node_values_string_new(VISU_NODE_ARRAY(data),
1711 DATA_LABEL_ID));
1712 visu_data_addNodeProperties(data, vals);
1713 }
1714 return VISU_NODE_VALUES_STRING(vals);
1715 }
1716 /**
1717 * visu_data_getNodeLabelAt:
1718 * @data: a #VisuData object.
1719 * @node: a #VisuNode from @data.
1720 *
1721 * Retrieves the label associated to @node in @data.
1722 *
1723 * Since: 3.8
1724 *
1725 * Returns: a label.
1726 **/
visu_data_getNodeLabelAt(const VisuData * data,const VisuNode * node)1727 const gchar* visu_data_getNodeLabelAt(const VisuData *data, const VisuNode *node)
1728 {
1729 const VisuNodeValues *vals;
1730
1731 vals = g_hash_table_lookup(data->priv->nodeProperties, DATA_LABEL_ID);
1732 if (!vals)
1733 return (const gchar*)0;
1734
1735 return visu_node_values_string_getAt(VISU_NODE_VALUES_STRING(vals),
1736 node);
1737 }
1738
1739 /**
1740 * visu_data_applyTransformationsFromCLI:
1741 * @data: a #VisuData object.
1742 * @error: an error location.
1743 *
1744 * Apply the extension and translation expressed in the command-line
1745 * arguments to @data.
1746 *
1747 * Since: 3.8
1748 *
1749 * Returns: TRUE on success.
1750 **/
visu_data_applyTransformationsFromCLI(VisuData * data,GError ** error)1751 gboolean visu_data_applyTransformationsFromCLI(VisuData *data, GError **error)
1752 {
1753 gboolean isBox;
1754 float *translations, *extension;
1755 VisuVibration *vib;
1756
1757 /* translate argument */
1758 translations = commandLineGet_translation(&isBox);
1759 if (translations && !isBox)
1760 visu_pointset_setTranslationPeriodic(VISU_POINTSET(data), translations, TRUE);
1761 else if (translations && isBox)
1762 visu_pointset_setBoxTranslation(VISU_POINTSET(data), translations, TRUE);
1763 visu_pointset_setTranslationActive(VISU_POINTSET(data),
1764 (translations != (float*)0));
1765
1766 /* expand argument */
1767 extension = commandLineGet_extension();
1768 if (extension)
1769 visu_box_setExtension(visu_boxed_getBox(VISU_BOXED(data)), extension);
1770 visu_box_setExtensionActive(visu_boxed_getBox(VISU_BOXED(data)),
1771 (extension != (float*)0));
1772
1773 /* Vibration displacements. */
1774 vib = visu_data_getVibration(data, 0);
1775 if (commandLineGet_phononMode() >= 0 && !vib)
1776 g_warning(_("option '--phonon-mode' has been given but"
1777 " no phonons are available."));
1778 else if (commandLineGet_phononMode() >= 0)
1779 visu_vibration_setCurrentMode(vib, commandLineGet_phononMode(), error);
1780 if (error && *error)
1781 return FALSE;
1782 if (commandLineGet_phononTime() >= 0.f && !vib)
1783 g_warning(_("option '--time-opffset' has been given but"
1784 " no phonons are available."));
1785 else if (commandLineGet_phononTime() >= 0)
1786 visu_vibration_setTime(vib, commandLineGet_phononTime());
1787 if (commandLineGet_phononAmpl() >= 0.f && !vib)
1788 g_warning(_("option '--phonon-amplitude' has been given but"
1789 " no phonons are available."));
1790 else if (commandLineGet_phononAmpl() >= 0)
1791 visu_vibration_setAmplitude(vib, commandLineGet_phononAmpl());
1792
1793 return TRUE;
1794 }
1795