1 /*   EXTRAITS DE LA LICENCE
2 	Copyright CEA, contributeurs : Damien
3 	CALISTE, laboratoire L_Sim, (2016)
4 
5 	Adresse mèl :
6 	CALISTE, damien P caliste AT cea P fr.
7 
8 	Ce logiciel est un programme informatique servant à visualiser des
9 	structures atomiques dans un rendu pseudo-3D.
10 
11 	Ce logiciel est régi par la licence CeCILL soumise au droit français et
12 	respectant les principes de diffusion des logiciels libres. Vous pouvez
13 	utiliser, modifier et/ou redistribuer ce programme sous les conditions
14 	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA
15 	sur le site "http://www.cecill.info".
16 
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 
22 /*   LICENCE SUM UP
23 	Copyright CEA, contributors : Damien
24 	CALISTE, laboratoire L_Sim, (2016)
25 
26 	E-mail address:
27 	CALISTE, damien P caliste AT cea P fr.
28 
29 	This software is a computer program whose purpose is to visualize atomic
30 	configurations in 3D.
31 
32 	This software is governed by the CeCILL  license under French law and
33 	abiding by the rules of distribution of free software.  You can  use,
34 	modify and/ or redistribute the software under the terms of the CeCILL
35 	license as circulated by CEA, CNRS and INRIA at the following URL
36 	"http://www.cecill.info".
37 
38 	The fact that you are presently reading this means that you have had
39 	knowledge of the CeCILL license and that you accept its terms. You can
40 	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
41 */
42 
43 #include "floatProp.h"
44 
45 #include <math.h>
46 
47 /**
48  * SECTION:floatProp
49  * @short_description: define a #VisuNodeValues object to handle any
50  * array of floats.
51  *
52  * <para>Defines a #VisuNodeValues object to store floating point
53  * arrays on every nodes and get notification for them.</para>
54  */
55 
56 struct _VisuNodeValuesFarrayPrivate
57 {
58   gboolean dispose_has_run;
59 
60   gboolean dirty;
61   gfloat min, max, nrm2;
62   gfloat *zeros;
63 
64   GArray *readMinMax; /* Values min and max read for each column. */
65 
66   gchar *file;
67 };
68 
69 enum
70   {
71     PROP_0,
72     MIN_PROP,
73     MAX_PROP,
74     NRM2_PROP,
75     READ_MM_PROP,
76     FILE_PROP,
77     N_PROP
78   };
79 static GParamSpec *_properties[N_PROP];
80 
81 static void visu_node_values_farray_finalize (GObject* obj);
82 static void visu_node_values_farray_get_property(GObject* obj, guint property_id,
83                                                  GValue *value, GParamSpec *pspec);
84 static gboolean _setAt(VisuNodeValues *vals, const VisuNode *node,
85                        GValue *value);
86 static gfloat _nrm2(const VisuNodeValuesFarray *vect, const GValue *value);
87 static void _compute(VisuNodeValuesFarray *vect);
88 static void onDimensionSet(VisuNodeValuesFarray *vect, const GParamSpec *pspec, gpointer data);
89 
90 G_DEFINE_TYPE_WITH_CODE(VisuNodeValuesFarray, visu_node_values_farray, VISU_TYPE_NODE_VALUES,
91                         G_ADD_PRIVATE(VisuNodeValuesFarray))
92 
93 static void visu_node_values_farray_class_init(VisuNodeValuesFarrayClass *klass)
94 {
95   /* Connect the overloading methods. */
96   G_OBJECT_CLASS(klass)->finalize = visu_node_values_farray_finalize;
97   /* G_OBJECT_CLASS(klass)->set_property = visu_node_values_farray_set_property; */
98   G_OBJECT_CLASS(klass)->get_property = visu_node_values_farray_get_property;
99   VISU_NODE_VALUES_CLASS(klass)->setAt = _setAt;
100   klass->nrm2 = _nrm2;
101 
102   /**
103    * VisuNodeValuesFarray::minimum:
104    *
105    * Holds the norm of the minimum value.
106    *
107    * Since: 3.8
108    */
109   _properties[MIN_PROP] =
110     g_param_spec_float("minimum", "Minimum", "minimum norm",
111                        0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
112   /**
113    * VisuNodeValuesFarray::maximum:
114    *
115    * Holds the norm of the maximum value.
116    *
117    * Since: 3.8
118    */
119   _properties[MAX_PROP] =
120     g_param_spec_float("maximum", "Maximum", "maximum norm",
121                        0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
122   /**
123    * VisuNodeValuesFarray::square-norm:
124    *
125    * Holds the square norm of the values.
126    *
127    * Since: 3.8
128    */
129   _properties[NRM2_PROP] =
130     g_param_spec_float("square-norm", "Square-norm", "Square norm",
131                        0.f, G_MAXFLOAT, 0.f, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
132   /**
133    * VisuNodeValuesFarray::data-min-max:
134    *
135    * Min / max values per dimension of the stored data.
136    *
137    * Since: 3.8
138    */
139   _properties[READ_MM_PROP] =
140     g_param_spec_boxed("data-min-max", "Data min/max",
141                        "min / max values of data",
142                        G_TYPE_ARRAY,
143                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
144   /**
145    * VisuNodeValuesFarray::source-file:
146    *
147    * Name of the source file the data come from.
148    *
149    * Since: 3.8
150    */
151   _properties[FILE_PROP] = g_param_spec_string("source-file", "Source file",
152                                                "Source file if any",
153                                                (const gchar*)0,
154                                                G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
155 
156   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties);
157 }
158 
159 static void visu_node_values_farray_init(VisuNodeValuesFarray *self)
160 {
161   DBG_fprintf(stderr, "Node Values Float : initialise %p.\n", (gpointer)self);
162 
163   self->priv = visu_node_values_farray_get_instance_private(self);
164 
165   self->priv->readMinMax      = g_array_new(FALSE, FALSE, sizeof(float) * 2);
166   self->priv->file            = (gchar*)0;
167   self->priv->dirty           = TRUE;
168 
169   g_signal_connect(G_OBJECT(self), "notify::n-elements",
170                    G_CALLBACK(onDimensionSet), (gpointer)0);
171 }
172 static void onDimensionSet(VisuNodeValuesFarray *vect,
173                            const GParamSpec *pspec _U_, gpointer data _U_)
174 {
175   vect->priv->zeros = g_malloc0(sizeof(float) * visu_node_values_getDimension(VISU_NODE_VALUES(vect)));
176 }
177 
178 /* This method is called once only. */
179 static void visu_node_values_farray_finalize(GObject* obj)
180 {
181   VisuNodeValuesFarray *self;
182 
183   DBG_fprintf(stderr, "Node Values Float : finalize %p.\n", (gpointer)obj);
184 
185   g_return_if_fail(obj);
186 
187   self = VISU_NODE_VALUES_FARRAY(obj);
188   g_free(self->priv->zeros);
189   g_array_unref(self->priv->readMinMax);
190   g_free(self->priv->file);
191 
192   /* Chain up to the parent class */
193   G_OBJECT_CLASS(visu_node_values_farray_parent_class)->finalize(obj);
194 }
195 static void visu_node_values_farray_get_property(GObject* obj, guint property_id,
196                                                  GValue *value, GParamSpec *pspec)
197 {
198   VisuNodeValuesFarray *self = VISU_NODE_VALUES_FARRAY(obj);
199 
200   switch (property_id)
201     {
202     case MIN_PROP:
203       g_value_set_float(value, visu_node_values_farray_min(self));
204       break;
205     case MAX_PROP:
206       g_value_set_float(value, visu_node_values_farray_max(self));
207       break;
208     case NRM2_PROP:
209       g_value_set_float(value, visu_node_values_farray_nrm2(self));
210       break;
211     case READ_MM_PROP:
212       _compute(self);
213       g_value_set_boxed(value, self->priv->readMinMax);
214       break;
215     case FILE_PROP:
216       g_value_set_static_string(value, self->priv->file);
217       break;
218     default:
219       /* We don't have any other property... */
220       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
221       break;
222     }
223 }
224 static gfloat _nrm2(const VisuNodeValuesFarray *vect, const GValue *value)
225 {
226   gfloat *diff, nrm2;
227   guint i, ln;
228 
229   diff = (gfloat*)g_value_get_pointer(value);
230   if (diff)
231     {
232       ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect));
233       nrm2 = 0.f;
234       for (i = 0; i < ln; i++)
235         nrm2 += diff[i] * diff[i];
236       return nrm2;
237     }
238   else
239     return 0.f;
240 }
241 
242 /**
243  * visu_node_values_farray_new:
244  * @arr: a #VisuNodeArray object.
245  * @label: a translatable label.
246  * @dimension: a integer value.
247  *
248  * Create a new farray field located on nodes, storing @dimension
249  * floats per node.
250  *
251  * Since: 3.8
252  *
253  * Returns: (transfer full): a newly created #VisuNodeValuesFarray object.
254  **/
255 VisuNodeValuesFarray* visu_node_values_farray_new(VisuNodeArray *arr,
256                                                   const gchar *label,
257                                                   guint dimension)
258 {
259   VisuNodeValuesFarray *vals;
260 
261   vals = VISU_NODE_VALUES_FARRAY(g_object_new(VISU_TYPE_NODE_VALUES_FARRAY,
262                                               "nodes", arr, "label", label,
263                                               "type", G_TYPE_FLOAT,
264                                               "n-elements", dimension, NULL));
265   return vals;
266 }
267 /**
268  * visu_node_values_farray_new_fromFile:
269  * @arr: a #VisuNodeArray object.
270  * @label: a label.
271  * @filename: a filename.
272  * @error: an error location.
273  *
274  * Parse @filename to read floating point values and creates a new
275  * #VisuNodeValuesFarray object based on @arr. If an error occurs, an
276  * empty #VisuNodeValuesFarray object is created.
277  *
278  * Since: 3.8
279  *
280  * Returns: (transfer full): a newly created #VisuNodeValuesFarray object.
281  **/
282 VisuNodeValuesFarray* visu_node_values_farray_new_fromFile(VisuNodeArray *arr,
283                                                            const gchar *label,
284                                                            const gchar *filename,
285                                                            GError **error)
286 {
287   guint nColumns, nbNodes;
288   GArray *data;
289   VisuNodeValuesFarray *vals;
290 
291   nbNodes = visu_node_array_getNNodes(arr);
292   data = tool_array_sizedFromFile(filename, nbNodes, &nColumns, error);
293   if (!data)
294     return visu_node_values_farray_new(arr, label, 1);
295 
296   vals = visu_node_values_farray_new(arr, label, nColumns);
297   visu_node_values_farray_set(vals, data);
298   vals->priv->file = g_strdup(filename);
299 
300   g_array_free(data, TRUE);
301 
302   return vals;
303 }
304 
305 /**
306  * visu_node_values_farray_min:
307  * @vect: a #VisuNodeValuesFarray object.
308  *
309  * Computes and returns the smallest farray in the field.
310  *
311  * Since: 3.8
312  *
313  * Returns: the minimum farray norm.
314  **/
315 gfloat visu_node_values_farray_min(VisuNodeValuesFarray *vect)
316 {
317   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), G_MAXFLOAT);
318   _compute(vect);
319   return vect->priv->min;
320 }
321 /**
322  * visu_node_values_farray_max:
323  * @vect: a #VisuNodeValuesFarray object.
324  *
325  * Computes and returns the longest farray in the field.
326  *
327  * Since: 3.8
328  *
329  * Returns: the maximum farray norm.
330  **/
331 gfloat visu_node_values_farray_max(VisuNodeValuesFarray *vect)
332 {
333   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), -1.f);
334   _compute(vect);
335   return vect->priv->max;
336 }
337 /**
338  * visu_node_values_farray_nrm2:
339  * @vect: a #VisuNodeValuesFarray object.
340  *
341  * Computes and returns the sum of square norm all farrays in the field.
342  *
343  * Since: 3.8
344  *
345  * Returns: the square norm of the farray field.
346  **/
347 gfloat visu_node_values_farray_nrm2(VisuNodeValuesFarray *vect)
348 {
349   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), -1.f);
350   _compute(vect);
351   return vect->priv->nrm2;
352 }
353 /**
354  * visu_node_values_farray_getColumnMinMax:
355  * @vect: the #VisuNodeValuesFarray object.
356  * @minMax: (array fixed-size=2) (out): an allocated array of two
357  * floating point values ;
358  * @column: an integer.
359  *
360  * This method is used to retrieve the minimum and the maximum
361  * values of the column designed by the @column argument. Column
362  * are numbered beginning at 0.
363  *
364  * Returns: FALSE if @column < 0 or if @column is greater than the number
365  *          of read column or if no file has been set.
366  */
367 gboolean visu_node_values_farray_getColumnMinMax(VisuNodeValuesFarray *vect,
368                                                  float minMax[2], guint column)
369 {
370   float *minmax;
371 
372   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), FALSE);
373 
374   _compute(vect);
375   g_return_val_if_fail(column < vect->priv->readMinMax->len, FALSE);
376 
377   minmax = &g_array_index(vect->priv->readMinMax, float, column * 2);
378   minMax[0] = minmax[0];
379   minMax[1] = minmax[1];
380   return TRUE;
381 }
382 static void _compute(VisuNodeValuesFarray *vect)
383 {
384   float nrm2;
385   gboolean valid;
386   guint i, ln;
387   VisuNodeValuesIter iter;
388   VisuNodeValuesFarrayClass *klass = VISU_NODE_VALUES_FARRAY_GET_CLASS(vect);
389   float init[2] = {G_MAXFLOAT, -G_MAXFLOAT};
390   float *data, *minmax;
391 
392   DBG_fprintf(stderr, "Node Values Float (%p): recompute %d.\n",
393               (gpointer)vect, vect->priv->dirty);
394   if (!vect->priv->dirty)
395     return;
396   vect->priv->dirty = FALSE;
397 
398   vect->priv->nrm2 = 0.f;
399   vect->priv->min = G_MAXFLOAT;
400   vect->priv->max = 0.f;
401 
402   valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE,
403                                     VISU_NODE_VALUES(vect));
404   while (valid)
405     {
406       nrm2 = klass->nrm2(vect, &iter.value);
407       if (nrm2 >= 0.f)
408         {
409           vect->priv->nrm2 += nrm2;
410           vect->priv->min = MIN(vect->priv->min, nrm2);
411           vect->priv->max = MAX(vect->priv->max, nrm2);
412         }
413       valid = visu_node_values_iter_next(&iter);
414     }
415   vect->priv->min = sqrt(vect->priv->min);
416   vect->priv->max = sqrt(vect->priv->max);
417 
418   ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect));
419   g_array_set_size(vect->priv->readMinMax, ln);
420   /* Check for minMax values for each column. */
421   for (i = 0; i < ln; i++)
422     g_array_insert_vals(vect->priv->readMinMax, i, init, 1);
423   for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE,
424                                  VISU_NODE_VALUES(vect));
425        iter.iter.node; visu_node_values_iter_next(&iter))
426     {
427       data = (float*)g_value_get_pointer(&iter.value);
428       if (!data)
429         continue;
430       for (i = 0; i < ln; i++)
431         {
432           minmax = &g_array_index(vect->priv->readMinMax, float, i * 2);
433           if (data[i] < minmax[0])
434             minmax[0] = data[i];
435           if (data[i] > minmax[1])
436             minmax[1] = data[i];
437         }
438     }
439 }
440 /**
441  * visu_node_values_farray_getAt:
442  * @vect: a #VisuNodeValuesFarray object.
443  * @node: a #VisuNode object.
444  *
445  * Retrieves the float array hosted on @node.
446  *
447  * Since: 3.8
448  *
449  * Returns: (transfer none): the coordinates of
450  * float array for @node.
451  **/
452 const gfloat* visu_node_values_farray_getAt(VisuNodeValuesFarray *vect,
453                                             const VisuNode *node)
454 {
455   GValue diffValue = G_VALUE_INIT;
456   const gfloat *diff;
457 
458   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), NULL);
459 
460   visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue);
461   diff = (const gfloat*)g_value_get_pointer(&diffValue);
462   return diff;  /* ? diff : vect->priv->zeros; */
463 }
464 
465 /**
466  * visu_node_values_farray_getAtIter:
467  * @vect: a #VisuNodeValuesFarray object.
468  * @iter: an iterator on @vect.
469  *
470  * Provide the floats stored in @vect at @iter.
471  *
472  * Since: 3.8
473  *
474  * Returns: a pointer to the float array.
475  **/
476 const gfloat* visu_node_values_farray_getAtIter(const VisuNodeValuesFarray *vect,
477                                                 const VisuNodeValuesIter *iter)
478 {
479   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), NULL);
480   g_return_val_if_fail(iter, NULL);
481 
482   return (const gfloat*)g_value_get_pointer(&iter->value);
483 }
484 
485 /**
486  * visu_node_values_farray_getFloatAt:
487  * @vect: a #VisuNodeValuesFarray object.
488  * @node: a #VisuNode pointer.
489  * @column: a column id.
490  *
491  * Retrieves the float value stored for @node at @column, if any.
492  *
493  * Since: 3.8
494  *
495  * Returns: a float value.
496  **/
497 gfloat visu_node_values_farray_getFloatAt(const VisuNodeValuesFarray *vect,
498                                           const VisuNode *node,
499                                           guint column)
500 {
501   GValue diffValue = G_VALUE_INIT;
502   const gfloat *vals;
503 
504   g_return_val_if_fail(column < visu_node_values_getDimension(VISU_NODE_VALUES(vect)), 0.f);
505 
506   visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &diffValue);
507   vals = (const gfloat*)g_value_get_pointer(&diffValue);
508 
509   return vals ? vals[column] : 0.f;
510 }
511 
512 /**
513  * visu_node_values_farray_getFloatAtIter:
514  * @vect: a #VisuNodeValuesFarray object.
515  * @iter: a #VisuNodeValuesIter object.
516  * @column: a column id.
517  *
518  * Retrieves the float value stored for the current iteration of @iter
519  * for the column @column. @iter must be running on @vect.
520  *
521  * Since: 3.8
522  *
523  * Returns: a float value.
524  **/
525 gfloat visu_node_values_farray_getFloatAtIter(const VisuNodeValuesFarray *vect,
526                                               const VisuNodeValuesIter *iter,
527                                               guint column)
528 {
529   const gfloat *vals;
530 
531   g_return_val_if_fail(iter && iter->vals == VISU_NODE_VALUES(vect), 0.f);
532   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), 0.f);
533   g_return_val_if_fail(column < visu_node_values_getDimension(VISU_NODE_VALUES(vect)), 0.f);
534 
535   vals = (const gfloat*)g_value_get_pointer(&iter->value);
536 
537   return vals ? vals[column] : 0.f;
538 }
539 
540 static gboolean _setAt(VisuNodeValues *vect, const VisuNode *node,
541                        GValue *value)
542 {
543   gboolean res;
544 
545   VISU_NODE_VALUES_FARRAY(vect)->priv->dirty = TRUE;
546 
547   /* Chain up to parent. */
548   res = VISU_NODE_VALUES_CLASS(visu_node_values_farray_parent_class)->setAt(vect, node, value);
549 
550   if (res)
551     {
552       g_object_notify_by_pspec(G_OBJECT(vect), _properties[READ_MM_PROP]);
553       g_object_notify_by_pspec(G_OBJECT(vect), _properties[MIN_PROP]);
554       g_object_notify_by_pspec(G_OBJECT(vect), _properties[MAX_PROP]);
555       g_object_notify_by_pspec(G_OBJECT(vect), _properties[NRM2_PROP]);
556     }
557 
558   return res;
559 }
560 /**
561  * visu_node_values_farray_setAt:
562  * @vect: a #VisuNodeValuesFarray object.
563  * @node: a #VisuNode object.
564  * @vals: (array length=ln): farray coordinates.
565  * @ln: a length.
566  *
567  * Changes the float array hosted at @node for one of values defined
568  * by @vals.
569  *
570  * Since: 3.8
571  *
572  * Returns: TRUE if farray for @node is indeed changed.
573  **/
574 gboolean visu_node_values_farray_setAt(VisuNodeValuesFarray *vect,
575                                        const VisuNode *node,
576                                        const gfloat *vals,
577                                        guint ln)
578 {
579   gfloat *old;
580   guint i;
581   gboolean changed;
582   GValue value = {0, {{0}, {0}}};
583 
584   g_return_val_if_fail(visu_node_values_getDimension(VISU_NODE_VALUES(vect)) == ln, FALSE);
585 
586   visu_node_values_getAt(VISU_NODE_VALUES(vect), node, &value);
587   old = (gfloat*)g_value_get_pointer(&value);
588   if (old)
589     {
590       changed = FALSE;
591       for (i = 0; i < ln && !changed; i++)
592         changed = (old[i] != vals[i]);
593       if (!changed)
594         return FALSE;
595     }
596 
597   g_value_set_pointer(&value, (gpointer)vals);
598   return visu_node_values_setAt(VISU_NODE_VALUES(vect), node, &value);
599 }
600 /**
601  * visu_node_values_farray_setAtDbl:
602  * @vect: a #VisuNodeValuesFarray object.
603  * @node: a #VisuNode object.
604  * @vals: (array fixed-size=3): farray coordinates.
605  * @ln: a length.
606  *
607  * Same as visu_node_values_farray_setAt() but for double values.
608  *
609  * Since: 3.8
610  *
611  * Returns: TRUE if farray for @node is indeed changed.
612  **/
613 gboolean visu_node_values_farray_setAtDbl(VisuNodeValuesFarray *vect,
614                                           const VisuNode *node,
615                                           const double *vals,
616                                           guint ln)
617 {
618   guint i;
619   gfloat *farr;
620   gboolean ret;
621 
622   g_return_val_if_fail(visu_node_values_getDimension(VISU_NODE_VALUES(vect)) == ln, FALSE);
623 
624   farr = g_malloc(sizeof(gfloat) * ln);
625   for (i = 0; i < ln; i++)
626     farr[i] = vals[i];
627   ret = visu_node_values_farray_setAt(vect, node, farr, ln);
628   g_free(farr);
629   return ret;
630 }
631 /**
632  * visu_node_values_farray_set:
633  * @vect: a #VisuNodeValuesFarray object.
634  * @data: (element-type float): some farray coordinates.
635  *
636  * Assigns the coordinates stored in @data to each nodes in @vect.
637  *
638  * Since: 3.8
639  *
640  * Returns: TRUE if @data has the same size as @vect.
641  **/
642 gboolean visu_node_values_farray_set(VisuNodeValuesFarray *vect,
643                                      const GArray *data)
644 {
645   guint i, ln;
646   gboolean valid;
647   VisuNodeValuesIter iter;
648 
649   ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect));
650   g_return_val_if_fail(data && data->len % ln == 0, FALSE);
651 
652   g_object_freeze_notify(G_OBJECT(vect));
653 
654   i = 0;
655   valid = visu_node_values_iter_new(&iter, ITER_NODES_BY_NUMBER,
656                                     VISU_NODE_VALUES(vect));
657   while (valid && i + ln <= data->len)
658     {
659       visu_node_values_farray_setAt(vect, iter.iter.node,
660                                     &g_array_index(data, float, i),
661                                     ln);
662       i += ln;
663       valid = visu_node_values_iter_next(&iter);
664     }
665 
666   g_object_thaw_notify(G_OBJECT(vect));
667 
668   return (i == data->len);
669 }
670 
671 /**
672  * visu_node_values_farray_getFile:
673  * @vect: a #VisuNodeValuesFarray object.
674  *
675  * Retrieve the filename from which the values have been read, if any.
676  *
677  * Since: 3.8
678  *
679  * Returns: a filename.
680  **/
681 const gchar* visu_node_values_farray_getFile(const VisuNodeValuesFarray *vect)
682 {
683   g_return_val_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect), (const gchar*)0);
684 
685   return vect->priv->file;
686 }
687 
688 /**
689  * visu_node_values_farray_scale:
690  * @vect: a #VisuNodeValuesFarray object.
691  * @factor: a factor.
692  *
693  * Multiply every element of @vect by @factor.
694  *
695  * Since: 3.8
696  **/
697 void visu_node_values_farray_scale(VisuNodeValuesFarray *vect, gfloat factor)
698 {
699   guint i, ln;
700   VisuNodeValuesIter iter;
701   gfloat *data;
702 
703   g_return_if_fail(VISU_IS_NODE_VALUES_FARRAY(vect));
704 
705   if (factor == 1.f)
706     return;
707 
708   vect->priv->dirty = TRUE;
709 
710   ln = visu_node_values_getDimension(VISU_NODE_VALUES(vect));
711   for (visu_node_values_iter_new(&iter, ITER_NODES_BY_TYPE,
712                                  VISU_NODE_VALUES(vect));
713        iter.iter.node; visu_node_values_iter_next(&iter))
714     {
715         data = (gfloat*)g_value_get_pointer(&iter.value);
716         if (!data)
717           continue;
718         for (i = 0; i < ln; i++)
719           data[i] *= factor;
720     }
721 }
722