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_nodes.h"
45 
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #include "visu_tools.h"
50 #include "coreTools/toolMatrix.h"
51 
52 /**
53  * SECTION:visu_nodes
54  * @short_description: Defines the elementary structure to store
55  * informations about an element in a box.
56  *
57  * <para>In V_Sim, elements are drawn in a box. The #VisuNode
58  * structure is used to represent an instance of an element position
59  * somewhere in the box. This element can have several characteristics
60  * such as its translation or its visibility.</para>
61  *
62  * <para>All nodes are stored in a #VisuData object in a two
63  * dimensional array. The first dimension is indexed by the
64  * #VisuElement of the node and the second corresponds to the number
65  * of this node for this element. When a node is own by a #VisuData,
66  * the two integers, that control the indexes in this array, are not
67  * negative. See the #VisuNode structure for further
68  * explanations.</para>
69  *
70  * <para>The only basic informations own by the #VisuNode structure is
71  * basicaly its position. To add further informations (such as
72  * orientation for the spin), define a node property using
73  * visu_node_array_property_newPointer().</para>
74  */
75 
76 /**
77  * VisuNode:
78  * @xyz: (in) (array fixed-size=3): an array of three floating point values that positions the node in (x, y, z) ;
79  * @translation: (in) (array fixed-size=3): an array of three floating point values that translates the
80  *               node to its drawn position from (x, y, z) ;
81  * @number: an integer that corresponds to its position in the entry file, it references
82  *          also the node itself in the array 'fromNumberToVisuNode' of the #VisuData
83  *          that contains the node ;
84  * @posElement: an integer that is the position of the #VisuElement of the node
85  *              in the array 'fromIntToVisuElement' of the #VisuData object that
86  *              contains the node ;
87  * @posNode: an integer that is the position of the node itself in the array
88  *           'nodes' of the #VisuData object that contains the node ;
89  * @rendered: a boolean to store if the node is drwn or not.
90  *
91  * Structure to store primary data of a node.
92  */
93 
94 /* Local routines. */
95 static void freeNodePropStruct(gpointer data);
96 static void removeNodeProperty(gpointer key, gpointer value, gpointer data);
97 static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data);
98 static void reallocNodeProperty(gpointer key, gpointer value, gpointer data);
99 static void allocateNodeProp(gpointer key, gpointer value, gpointer data);
100 static void createNodeproperty(gpointer key, gpointer value, gpointer data);
101 static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle, int oldNodeId);
102 static void freeElePropStruct(gpointer data);
103 
104 /* The number of nodes to be reallocated each time the visu_node_array_getNewNode()
105    is called. */
106 #define REALLOCATION_STEP 100
107 
108 /* The key of the original node property. */
109 #define ORIGINAL_ID       "originalId"
110 
111 struct twoNodes
112 {
113   VisuNode *oldNode;
114   VisuNode *newNode;
115 };
116 
117 typedef struct _VisuNodeArrayPrivate VisuNodeArrayPrivate;
118 struct _VisuNodeProperty
119 {
120   /* A label to define the property. */
121   gchar *name;
122 
123   /* A pointer to the array of nodes these properties are related to. */
124   VisuNodeArray *array;
125 
126   /* The type of the property. */
127   GType gtype;
128 
129   /* This table has the same size and structure
130      than the node array object it is related to.
131      Only one of the following data array is allocated. */
132   gpointer **data_pointer;
133   int **data_int;
134 
135   /* In the case of pointer data, one can give the new, copy and free routine. */
136   /* This method is called for each stored token,
137      if not NULL when the table is freed. */
138   GFunc freeTokenFunc;
139   /* This method is used to create/copy a token of the data array. */
140   GCopyFunc newOrCopyTokenFunc;
141   /* This value stores a pointer on a user data given when
142      the object is created. This pointer is given to the copy
143      or the free function. */
144   gpointer user_data;
145 };
146 struct _ElementProperty
147 {
148   VisuNodeArrayElementPropertyInit init;
149   GArray *array;
150 };
151 
152 /* static gpointer node_copy(gpointer boxed) */
153 /* { */
154 /*   VisuNode *node; */
155 
156 /*   node = g_malloc(sizeof(VisuNode)); */
157 /*   DBG_fprintf(stderr, "Visu Node: copying node %p to %p.\n", boxed, (gpointer)node); */
158 /*   *node = *(VisuNode*)boxed; */
159 
160 /*   return (gpointer)node; */
161 /* } */
node_no_copy(gpointer boxed)162 static gpointer node_no_copy(gpointer boxed)
163 {
164   return boxed;
165 }
node_no_free(gpointer boxed _U_)166 static void node_no_free(gpointer boxed _U_)
167 {
168 }
visu_node_get_type(void)169 GType visu_node_get_type(void)
170 {
171   static GType g_define_type_id = 0;
172 
173   if (g_define_type_id == 0)
174     g_define_type_id = g_boxed_type_register_static("VisuNode", node_no_copy, node_no_free);
175   return g_define_type_id;
176 }
177 
178 /**
179  * visu_node_setCoordinates:
180  * @node: a #VisuNode object ;
181  * @xyz: (array fixed-size=3): new cartesian coordinates.
182  *
183  * This method is used to change coordinates of @node.
184  *
185  * Since: 3.7
186  *
187  * Returns: TRUE if the calling method should emit
188  * #VisuNodeArray::position-changed signal.
189  */
visu_node_setCoordinates(VisuNode * node,float xyz[3])190 gboolean visu_node_setCoordinates(VisuNode* node, float xyz[3])
191 {
192   g_return_val_if_fail(node, FALSE);
193 
194   if (node->xyz[0] == xyz[0] && node->xyz[1] == xyz[1] && node->xyz[2] == xyz[2])
195     return FALSE;
196   node->xyz[0] = xyz[0];
197   node->xyz[1] = xyz[1];
198   node->xyz[2] = xyz[2];
199   return TRUE;
200 }
201 
202 /**
203  * visu_node_setVisibility:
204  * @node: a #VisuNode object ;
205  * @visibility: a boolean.
206  *
207  * This method is used to turn on or off the drawing of the specified node.
208  *
209  * Returns: %TRUE if the visibility has changed.
210  */
visu_node_setVisibility(VisuNode * node,gboolean visibility)211 gboolean visu_node_setVisibility(VisuNode* node, gboolean visibility)
212 {
213   g_return_val_if_fail(node, FALSE);
214 
215   if (node->rendered == visibility)
216     return FALSE;
217   node->rendered = visibility;
218   return TRUE;
219 }
220 
221 /**
222  * visu_node_getVisibility:
223  * @node: a #VisuNode object.
224  *
225  * This method is used get the status of the drawing state of a node.
226  *
227  * Returns: true if the node is rendered, false otherwise.
228  */
visu_node_getVisibility(VisuNode * node)229 gboolean visu_node_getVisibility(VisuNode* node)
230 {
231   g_return_val_if_fail(node, FALSE);
232 
233   return node->rendered;
234 }
235 
236 /**
237  * visu_node_newValues:
238  * @node: an allocated #VisuNode object ;
239  * @xyz: (in) (array fixed-size=3): the coordinates to set.
240  *
241  * Set the coordinates and set all other values to default.
242  */
visu_node_newValues(VisuNode * node,float xyz[3])243 void visu_node_newValues(VisuNode *node, float xyz[3])
244 {
245   g_return_if_fail(node);
246 
247   DBG_fprintf(stderr, "Visu Node: set new position for node %d (%g;%g;%g).\n",
248               node->number, xyz[0], xyz[1], xyz[2]);
249   node->xyz[0]         = xyz[0];
250   node->xyz[1]         = xyz[1];
251   node->xyz[2]         = xyz[2];
252   node->translation[0] = 0.;
253   node->translation[1] = 0.;
254   node->translation[2] = 0.;
255   node->rendered       = TRUE;
256 }
257 
258 
259 /***************/
260 /* Node Arrays */
261 /***************/
262 
263 typedef struct _eleArr
264 {
265   VisuElement *ele;
266   /* Listeners on VisuElement signals. */
267   gulong rendered, maskable;
268   /* Number of nodes allocated (size of the nodes array) and number of
269      nodes physically present in the array for this element. */
270   guint nNodes, nStoredNodes;
271   /* Allocated space for nodes of this element. */
272   VisuNode *nodes;
273 } EleArr;
274 
275 typedef struct _nodeTable
276 {
277   /* A counter. */
278   guint idCounter;
279   /* This array gives access to the good VisuNode
280      when one has its number. This number is an integer ranging in
281      [0;idCounter[. This value is readable in the #VisuNode structure
282      as the number attribute. The current allocated size is stored in
283      @nNodes. */
284   /* GArray *array. */
285   VisuNode **array;
286   /* The total of allocated VisuNodes. */
287   guint nNodes;
288   /* The total of stored VisuNodes. */
289   guint nStoredNodes;
290 
291   GArray *popIncIds, *posChgIds;
292 } NodeTable;
293 
294 /* Local methods. */
295 static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element);
296 static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec, VisuElement *element);
297 static void _freeNodes(VisuNodeArray *nodeArray);
298 #define _getEleArr(priv, i) (&g_array_index(priv->elements, EleArr, i))
299 #define _getElement(priv, i) _getEleArr(priv, i)->ele
300 static void allocateEleProp(gpointer key, gpointer value, gpointer data);
301 /* static void freeEleProp(gpointer key, gpointer value, gpointer data); */
302 
303 /**
304  * VisuNodeArray:
305  *
306  * Opaque structure representing array of nodes object.
307  */
308 struct _VisuNodeArrayPrivate
309 {
310   gboolean dispose_has_run;
311 
312   /****************/
313   /* The elements */
314   /****************/
315   /* Stores for each element some related informations (see EleArr). */
316   GArray *elements;
317 
318   /*************/
319   /* The nodes */
320   /*************/
321   NodeTable nodeTable;
322 
323   /***********************/
324   /* The property arrays */
325   /***********************/
326   /* Properties of elements. */
327   GHashTable *eleProp;
328   /* This is a table to store data, reachable with string keys.
329      It should be accessed via visu_node_setproperty()
330      and visu_node_array_getProperty(). */
331   GHashTable *nodeProp;
332 
333   /* A convenient pointer on the original node property. */
334   VisuNodeProperty *origProp;
335   /* Total of original nodes. */
336   guint nOrigNodes;
337 };
338 
339 enum {
340   POPULATION_INCREASE_SIGNAL,
341   POPULATION_DECREASE_SIGNAL,
342   POSITION_CHANGED_SIGNAL,
343   ELEMENT_VISIBILITY_CHANGED_SIGNAL,
344   ELEMENT_PLANE_CHANGED_SIGNAL,
345   LAST_SIGNAL
346 };
347 static guint visu_node_array_signals[LAST_SIGNAL] = { 0 };
348 
349 enum
350   {
351     PROP_0,
352     NNODES_PROP,
353     NORIGS_PROP,
354     ELES_PROP,
355     N_PROP
356   };
357 static GParamSpec *properties[N_PROP];
358 
359 static void visu_node_array_dispose     (GObject* obj);
360 static void visu_node_array_finalize    (GObject* obj);
361 static void visu_node_array_get_property(GObject* obj, guint property_id,
362                                          GValue *value, GParamSpec *pspec);
363 static void visu_maskable_interface_init(VisuMaskableInterface *iface);
364 
365 G_DEFINE_TYPE_WITH_CODE(VisuNodeArray, visu_node_array, VISU_TYPE_OBJECT,
366                         G_ADD_PRIVATE(VisuNodeArray)
367                         G_IMPLEMENT_INTERFACE(VISU_TYPE_MASKABLE,
368                                               visu_maskable_interface_init))
369 
370 static gboolean _resetVisibility(VisuMaskable *self);
371 static GArray* _getMasked(const VisuMaskable *self);
372 
visu_node_array_class_init(VisuNodeArrayClass * klass)373 static void visu_node_array_class_init(VisuNodeArrayClass *klass)
374 {
375   DBG_fprintf(stderr, "Visu NodeArray: creating the class of the object.\n");
376 
377   /* Connect the overloading methods. */
378   G_OBJECT_CLASS(klass)->dispose  = visu_node_array_dispose;
379   G_OBJECT_CLASS(klass)->finalize = visu_node_array_finalize;
380   G_OBJECT_CLASS(klass)->get_property = visu_node_array_get_property;
381 
382   DBG_fprintf(stderr, "                - adding new signals ;\n");
383   /**
384    * VisuNodeArray::PopulationDecrease:
385    * @nodes: the object which received the signal ;
386    * @ids: (element-type guint) (array): an array of #VisuNode ids.
387    *
388    * Gets emitted when the number of nodes has changed,
389    * decreasing. @ids contains all removed ids.
390    * When emitted, nodes have already been removed, so no external
391    * routines should keep pointers on these nodes.
392    *
393    * Since: 3.4
394    */
395   visu_node_array_signals[POPULATION_DECREASE_SIGNAL] =
396     g_signal_new("PopulationDecrease", G_TYPE_FROM_CLASS (klass),
397                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
398                  0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
399                  G_TYPE_NONE, 1, G_TYPE_ARRAY);
400   /**
401    * VisuNodeArray::PopulationIncrease:
402    * @nodes: the object which received the signal ;
403    * @ids: (element-type guint) (array): an array of #VisuNode ids.
404    *
405    * Gets emitted when the number of nodes has changed,
406    * increasing. @ids contains all new ids.
407    *
408    * Since: 3.4
409    */
410   visu_node_array_signals[POPULATION_INCREASE_SIGNAL] =
411     g_signal_new("PopulationIncrease", G_TYPE_FROM_CLASS (klass),
412                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
413                  0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
414                  G_TYPE_NONE, 1, G_TYPE_ARRAY);
415   /**
416    * VisuNodeArray::position-changed:
417    * @nodes: the object which received the signal ;
418    * @ids: (allow-none) (element-type guint): ids of moved nodes.
419    *
420    * Gets emitted when one or more nodes have moved, because of
421    * translations or because the user has moved them manually.
422    *
423    * Since: 3.2
424    */
425   visu_node_array_signals[POSITION_CHANGED_SIGNAL] =
426     g_signal_new("position-changed", G_TYPE_FROM_CLASS (klass),
427                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
428                  0, NULL, NULL, g_cclosure_marshal_VOID__BOXED,
429                  G_TYPE_NONE, 1, G_TYPE_ARRAY, NULL);
430 
431   /**
432    * VisuNodeArray::ElementVisibilityChanged:
433    * @nodes: the object which received the signal ;
434    * @ele: the #VisuElement that has its visibility changed
435    *
436    * Gets emitted when the visibility characteristic of one element changes.
437    *
438    * Since: 3.8
439    */
440   visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL] =
441     g_signal_new("ElementVisibilityChanged", G_TYPE_FROM_CLASS(klass),
442                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
443                  0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
444                  G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL);
445   /**
446    * VisuNodeArray::ElementMaskableChanged:
447    * @nodes: the object which received the signal ;
448    * @ele: the #VisuElement that has its visibility changed
449    *
450    * Gets emitted when the maskable characteristic of one element changes.
451    *
452    * Since: 3.8
453    */
454   visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL] =
455     g_signal_new("ElementMaskableChanged", G_TYPE_FROM_CLASS(klass),
456                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
457                  0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
458                  G_TYPE_NONE, 1, VISU_TYPE_ELEMENT, NULL);
459 
460   /**
461    * VisuNodeArray::n-nodes:
462    *
463    * Total number of nodes.
464    *
465    * Since: 3.8
466    */
467   properties[NNODES_PROP] = g_param_spec_uint("n-nodes", "# nodes", "total number of nodes",
468                                               0, G_MAXUINT, 0, G_PARAM_READABLE);
469   /**
470    * VisuNodeArray::n-original-nodes:
471    *
472    * Total number of original nodes.
473    *
474    * Since: 3.8
475    */
476   properties[NORIGS_PROP] = g_param_spec_uint("n-original-nodes", "# original nodes",
477                                               "total number of original nodes",
478                                               0, G_MAXUINT, 0, G_PARAM_READABLE);
479   /**
480    * VisuNodeArray::elements:
481    *
482    * An array with the elements.
483    *
484    * Since: 3.8
485    */
486   properties[ELES_PROP] = g_param_spec_boxed("elements", "Elements", "all elements",
487                                              G_TYPE_ARRAY, G_PARAM_READABLE);
488 
489   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties);
490 
491   /* Create the boxed type of nodes. */
492   visu_node_get_type();
493 }
visu_maskable_interface_init(VisuMaskableInterface * iface)494 static void visu_maskable_interface_init(VisuMaskableInterface *iface)
495 {
496   iface->reset_visibility = _resetVisibility;
497   iface->get_masked = _getMasked;
498 }
499 
visu_node_array_init(VisuNodeArray * array)500 static void visu_node_array_init(VisuNodeArray *array)
501 {
502   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
503   DBG_fprintf(stderr, "Visu NodeArray: initializing a new object (%p).\n",
504 	      (gpointer)array);
505 
506   priv->dispose_has_run = FALSE;
507 
508   priv->elements      = g_array_new(FALSE, FALSE, sizeof(EleArr));
509 
510   priv->nodeTable.idCounter    = 0;
511   priv->nodeTable.nNodes       = 0;
512   priv->nodeTable.nStoredNodes = 0;
513   priv->nodeTable.array        = (VisuNode**)0;
514   priv->nodeTable.popIncIds    = (GArray*)0;
515   priv->nodeTable.posChgIds    = (GArray*)0;
516 
517   priv->eleProp       = g_hash_table_new_full(g_str_hash, g_str_equal,
518                                               NULL, freeElePropStruct);
519   priv->nodeProp      = g_hash_table_new_full(g_str_hash, g_str_equal,
520                                               NULL, freeNodePropStruct);
521 
522   /* We add a node property that is > 0 if the node is a duplicate
523      node and negative if not. The value is the node id that the
524      duplicate refers to. */
525   DBG_fprintf(stderr, " | create the original node property.\n");
526   priv->origProp = visu_node_array_property_newInteger(array, ORIGINAL_ID);
527   priv->nOrigNodes = 0;
528 }
529 
530 /* This method can be called several times.
531    It should unref all of its reference to
532    GObjects. */
visu_node_array_dispose(GObject * obj)533 static void visu_node_array_dispose(GObject* obj)
534 {
535   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));
536   guint i;
537   EleArr *ele;
538 
539   DBG_fprintf(stderr, "Visu NodeArray: dispose object %p.\n", (gpointer)obj);
540 
541   g_return_if_fail(priv);
542   if (priv->dispose_has_run)
543     return;
544   priv->dispose_has_run = TRUE;
545 
546   for (i = 0; i < priv->elements->len; i++)
547     {
548       ele = _getEleArr(priv, i);
549       g_signal_handler_disconnect(ele->ele, ele->rendered);
550       g_signal_handler_disconnect(ele->ele, ele->maskable);
551       g_object_unref(ele->ele);
552     }
553 
554   /* Chain up to the parent class */
555   G_OBJECT_CLASS(visu_node_array_parent_class)->dispose(obj);
556 }
557 /* This method is called once only. */
visu_node_array_finalize(GObject * obj)558 static void visu_node_array_finalize(GObject* obj)
559 {
560   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));
561 
562   g_return_if_fail(priv);
563 
564   DBG_fprintf(stderr, "Visu NodeArray: finalize object %p.\n", (gpointer)obj);
565 
566   /* We first remove the properties, before the node description because
567      these descriptions may be relevant. */
568   if (priv->nodeProp)
569     g_hash_table_destroy(priv->nodeProp);
570   if (priv->eleProp)
571     g_hash_table_destroy(priv->eleProp);
572   _freeNodes(VISU_NODE_ARRAY(obj));
573   g_array_free(priv->elements, TRUE);
574 
575   /* Chain up to the parent class */
576   DBG_fprintf(stderr, "Visu NodeArray: chain to parent.\n");
577   G_OBJECT_CLASS(visu_node_array_parent_class)->finalize(obj);
578   DBG_fprintf(stderr, "Visu NodeArray: freeing ... OK.\n");
579 }
visu_node_array_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)580 static void visu_node_array_get_property(GObject* obj, guint property_id,
581                                          GValue *value, GParamSpec *pspec)
582 {
583   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(obj));
584   GArray *eles;
585   guint i;
586   EleArr *arr;
587 
588   DBG_fprintf(stderr, "Visu NodeArray: get property '%s' -> ",
589 	      g_param_spec_get_name(pspec));
590   switch (property_id)
591     {
592     case NNODES_PROP:
593       g_value_set_uint(value, priv->nodeTable.nStoredNodes);
594       DBG_fprintf(stderr, "%d.\n", priv->nodeTable.nStoredNodes);
595       break;
596     case NORIGS_PROP:
597       g_value_set_uint(value, priv->nOrigNodes);
598       DBG_fprintf(stderr, "%d.\n", priv->nOrigNodes);
599       break;
600     case ELES_PROP:
601       eles = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*),
602                                priv->elements->len);
603       for (i = 0; i < priv->elements->len; i++)
604         {
605           arr = _getEleArr(priv, i);
606           g_array_append_val(eles, arr->ele);
607         }
608       g_value_take_boxed(value, eles);
609       DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
610       break;
611     default:
612       /* We don't have any other property... */
613       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
614       break;
615     }
616 }
617 
618 #if DEBUG == 1
_checkNodeTable(NodeTable * table)619 static void _checkNodeTable(NodeTable *table)
620 {
621   guint j;
622 
623   for (j = 0; j < table->idCounter; j++)
624     if (table->array[j] && table->array[j]->number != j)
625       g_warning("inconsistency on node number %d.", j);
626 }
627 #endif
_validNodeTableId(NodeTable * table,guint id)628 static gboolean _validNodeTableId(NodeTable *table, guint id)
629 {
630   g_return_val_if_fail(table, FALSE);
631 
632   return id < table->idCounter;
633 }
_increaseNodeTable(NodeTable * table,guint delta)634 static void _increaseNodeTable(NodeTable *table, guint delta)
635 {
636   table->nNodes += delta;
637   table->array = g_realloc(table->array, sizeof(VisuNode*) * table->nNodes);
638   memset(table->array + table->nNodes - delta, '\0', sizeof(VisuNode*) * delta);
639 }
_compactNodeTable(NodeTable * table)640 static void _compactNodeTable(NodeTable *table)
641 {
642   DBG_fprintf(stderr, "Visu NodeArray: compaction required (%d %d).\n",
643               table->idCounter, table->nNodes);
644   g_return_if_fail(table && table->idCounter <= table->nNodes);
645 
646   /* We get the last non NULL node pointer in the array array to make the
647      idCounter having this value to avoid to much reallocation of the array
648      array. */
649   for (; table->idCounter > 0 && !table->array[table->idCounter - 1];
650        table->idCounter -= 1);
651   DBG_fprintf(stderr, "Visu NodeArray: idCounter is set to %d.\n", table->idCounter);
652 }
_getFromId(NodeTable * table,guint number)653 static VisuNode* _getFromId(NodeTable *table, guint number)
654 {
655   g_return_val_if_fail(table && number < table->nNodes, (VisuNode*)0);
656 
657   return table->array[number];
658 }
_setAtId(NodeTable * table,guint number,VisuNode * node)659 static void _setAtId(NodeTable *table, guint number, VisuNode *node)
660 {
661   g_return_if_fail(table && number < table->nNodes);
662 
663   if (node && !table->array[number])
664     table->nStoredNodes += 1;
665   else if (!node && table->array[number])
666     table->nStoredNodes -= 1;
667   table->array[number] = node;
668 }
_addNodeTable(NodeTable * table,VisuNode * node)669 static void _addNodeTable(NodeTable *table, VisuNode *node)
670 {
671   g_return_if_fail(table && node);
672 
673   if (table->idCounter == table->nNodes)
674     _increaseNodeTable(table, REALLOCATION_STEP);
675 
676   node->number = table->idCounter;
677   _setAtId(table, node->number, node);
678   table->idCounter += 1;
679 }
680 
681 /**
682  * visu_node_array_allocate:
683  * @array: a #VisuNodeArray object.
684  * @elements: (in) (element-type VisuElement*):the size of nNodes.
685  * @nNodes: (in) (element-type guint): an array giving the number of nodes per element.
686  *
687  * Reallocate the internal arrays to match @elements and @nNodes.
688  */
visu_node_array_allocate(VisuNodeArray * array,GArray * elements,GArray * nNodes)689 void visu_node_array_allocate(VisuNodeArray *array,
690                               GArray *elements, GArray *nNodes)
691 {
692   guint i, j;
693   EleArr ele;
694   VisuElement *element;
695   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
696 
697   g_return_if_fail(priv);
698   g_return_if_fail(nNodes && nNodes->len > 0);
699   g_return_if_fail(elements && elements->len > 0);
700   g_return_if_fail(nNodes->len == elements->len);
701 
702   DBG_fprintf(stderr, "Visu NodeArray: allocating VisuElement data (+%d elements).\n",
703               elements->len);
704 
705   for(i = 0; i < elements->len; i++)
706     {
707       element = g_array_index(elements, VisuElement*, i);
708       if (visu_node_array_getElementId(array, element) < 0)
709         {
710           /* Create new element. */
711           ele.ele = g_object_ref(element);
712           ele.rendered =
713             g_signal_connect_swapped(G_OBJECT(element), "notify::rendered",
714                                      G_CALLBACK(onElementRenderChanged), array);
715           ele.maskable =
716             g_signal_connect_swapped(G_OBJECT(element), "notify::maskable",
717                                      G_CALLBACK(onElementPlaneChanged), array);
718           ele.nNodes = g_array_index(nNodes, guint, i);
719           ele.nStoredNodes = 0;
720           ele.nodes = g_malloc(sizeof(VisuNode) * ele.nNodes);
721           for (j = 0; j < ele.nNodes; j++)
722             {
723               ele.nodes[j].posElement = priv->elements->len;
724               ele.nodes[j].posNode    = j;
725             }
726 
727           priv->elements = g_array_append_val(priv->elements, ele);
728 
729           /* Increase the node table. */
730           _increaseNodeTable(&priv->nodeTable, ele.nNodes);
731 
732           /* Expand element properties for new element. */
733           g_hash_table_foreach(priv->eleProp, allocateEleProp, (gpointer)ele.ele);
734           /* Expand node properties for new element. */
735           g_hash_table_foreach(priv->nodeProp, allocateNodeProp, (gpointer)0);
736 
737           DBG_fprintf(stderr, " | add VisuElement '%p' -> '%s' (%ld) at %p.\n",
738                       (gpointer)element, element->name, ele.rendered,
739                       (gpointer)_getEleArr(priv, priv->elements->len - 1));
740           DBG_fprintf(stderr, " | %d nodes allocated.\n", ele.nNodes);
741         }
742       else
743         /* Reallocate existing element. */
744         visu_node_array_allocateNodesForElement(array, i, g_array_index(nNodes, guint, i));
745     }
746   DBG_fprintf(stderr, " | has now %d elements.\n", priv->elements->len);
747   DBG_fprintf(stderr, " | total number of allocated nodes %d.\n",
748 	      priv->nodeTable.nNodes);
749 
750   DBG_fprintf(stderr, " | size = %do\n",
751 	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
752                     sizeof(VisuNode) * priv->nodeTable.nNodes +
753 		    sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray)));
754 
755   g_object_notify_by_pspec(G_OBJECT(array), properties[ELES_PROP]);
756 }
757 /**
758  * visu_node_array_allocateByNames:
759  * @array: a #VisuNodeArray object;
760  * @nNodesPerElement: (in) (element-type guint): number of #VisuNode per VisuElement;
761  * @elementNames: (in) (element-type utf8): names of elements;
762  *
763  * This method allocates the storing part of the given #VisuNodeArray structure and
764  * store all the #VisuNodes.
765  */
visu_node_array_allocateByNames(VisuNodeArray * array,GArray * nNodesPerElement,GArray * elementNames)766 void visu_node_array_allocateByNames(VisuNodeArray *array,
767                                      GArray *nNodesPerElement,
768                                      GArray *elementNames)
769 {
770   GArray *elements;
771   guint i;
772   VisuElement *ele;
773 
774   DBG_fprintf(stderr, "Visu NodeArray: allocating %p from names.\n", (gpointer)array);
775 
776   elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), elementNames->len);
777   for (i = 0; i < elementNames->len; i++)
778     {
779       ele = visu_element_retrieveFromName(g_array_index(elementNames, gchar*, i),
780                                           (gboolean*)0);
781       g_array_append_val(elements, ele);
782     }
783   visu_node_array_allocate(array, elements, nNodesPerElement);
784   g_array_free(elements, TRUE);
785 }
_freeNodes(VisuNodeArray * nodeArray)786 static void _freeNodes(VisuNodeArray *nodeArray)
787 {
788   guint i;
789   EleArr *ele;
790   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
791 
792   DBG_fprintf(stderr, "Visu NodeArray: free storages of %p.\n", (gpointer)nodeArray);
793 
794   g_return_if_fail(priv);
795   if (priv->elements)
796     {
797       for (i = 0; i < priv->elements->len; i++)
798         {
799           ele = _getEleArr(priv, i);
800           if (!priv->dispose_has_run)
801             {
802               g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->rendered);
803               g_signal_handler_disconnect(G_OBJECT(ele->ele), ele->maskable);
804               g_object_unref(ele->ele);
805             }
806           g_free(ele->nodes);
807         }
808       g_array_set_size(priv->elements, 0);
809     }
810 
811   g_free(priv->nodeTable.array);
812   if (priv->nodeTable.popIncIds)
813     g_array_unref(priv->nodeTable.popIncIds);
814   if (priv->nodeTable.posChgIds)
815     g_array_unref(priv->nodeTable.posChgIds);
816   priv->nodeTable.array = (VisuNode**)0;
817   priv->nodeTable.idCounter      = 0;
818   priv->nodeTable.nNodes         = 0;
819   priv->nodeTable.nStoredNodes   = 0;
820   priv->nodeTable.popIncIds      = (GArray*)0;
821   priv->nodeTable.posChgIds      = (GArray*)0;
822   DBG_fprintf(stderr, "Visu NodeArray: freeing node array ... OK.\n");
823 }
824 
825 /**
826  * visu_node_array_freeNodes:
827  * @nodeArray: a #VisuNodeArray object.
828  *
829  * Deallocate all nodes of the object and related properties but keep
830  * the object alive.
831  **/
visu_node_array_freeNodes(VisuNodeArray * nodeArray)832 void visu_node_array_freeNodes(VisuNodeArray *nodeArray)
833 {
834   guint i;
835   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
836 
837   /* We first remove the properties, before the node description because
838      these descriptions may be relevant. */
839   g_return_if_fail(priv);
840   if (priv->nodeProp)
841     for (i = 0; i < priv->elements->len; i++)
842       g_hash_table_foreach(priv->nodeProp,
843                            removeNodePropertyForElement, GINT_TO_POINTER(i));
844   if (priv->eleProp)
845     g_hash_table_remove_all(priv->eleProp);
846 
847   _freeNodes(nodeArray);
848   g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
849   g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[ELES_PROP]);
850 
851   priv->origProp = visu_node_array_property_newInteger(nodeArray, ORIGINAL_ID);
852   priv->nOrigNodes = 0;
853 }
854 
855 /**
856  * visu_node_array_removeNodes:
857  * @nodeArray: a #VisuNodeArray object.
858  * @nodeNumbers: (element-type guint): an array of integers (negative terminated).
859  *
860  * Remove the given #VisuNode from the @nodeArray. The properties
861  * are also updated.
862  */
visu_node_array_removeNodes(VisuNodeArray * nodeArray,GArray * nodeNumbers)863 void visu_node_array_removeNodes(VisuNodeArray *nodeArray, GArray *nodeNumbers)
864 {
865   VisuNode *node;
866   guint i, iEle, iNode, number;
867   EleArr *ele;
868   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
869 
870   g_return_if_fail(priv && nodeNumbers);
871 
872   if (nodeNumbers->len == 0)
873     return;
874 
875   /* For each element in the given node array, we take the last node
876      of the same element and it takes it position. */
877   DBG_fprintf(stderr, "Visu Node: removing nodes from array %p (%d).\n",
878 	      (gpointer)nodeArray, nodeNumbers->len);
879   for (i = 0; i < nodeNumbers->len; i++)
880     {
881       number = g_array_index(nodeNumbers, guint, i);
882       node = _getFromId(&priv->nodeTable, number);
883       if (!node)
884         continue;
885       g_return_if_fail(node->number == number);
886 
887       iEle  = node->posElement;
888       iNode = node->posNode;
889 
890       ele = _getEleArr(priv, iEle);
891       ele->nStoredNodes -= 1;
892       if (priv->origProp->data_int[iEle][iNode] < 0)
893         priv->nOrigNodes -= 1;
894 
895       if (ele->nStoredNodes > 0)
896 	{
897 	  /* First, we copy the properties following the same scheme,
898 	     the last node of the given element is copy instead of
899 	     the given one. */
900 	  g_hash_table_foreach(priv->nodeProp, removeNodeProperty,
901                                ele->nodes + iNode);
902 
903 	  /* Then, we copy the node values themselves. */
904           ele->nodes[iNode] = ele->nodes[ele->nStoredNodes];
905 	  /* We update the index values. */
906 	  ele->nodes[iNode].posNode = iNode;
907 	  ele->nodes[iNode].number  = ele->nodes[ele->nStoredNodes].number;
908           _setAtId(&priv->nodeTable, ele->nodes[iNode].number, ele->nodes + iNode);
909 	}
910       /* Nullify the removed node. */
911       _setAtId(&priv->nodeTable, number, (VisuNode*)0);
912 
913       DBG_fprintf(stderr, "Visu NodeArray: %d removed, population for element %d is now:",
914                   number, iEle);
915       DBG_fprintf(stderr, " %d/%d # %d/%d\n", priv->nodeTable.nStoredNodes,
916 		  priv->nodeTable.nNodes, ele->nStoredNodes, ele->nNodes);
917     }
918   _compactNodeTable(&priv->nodeTable);
919   DBG_fprintf(stderr, " | size = %do\n",
920 	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
921                     sizeof(VisuNode) * priv->nodeTable.nNodes +
922 		    sizeof(VisuNode*) * priv->nodeTable.nNodes +
923                     sizeof(VisuNodeArray)));
924 
925   DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n");
926   g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
927   g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL],
928 		0, (gpointer)nodeNumbers, NULL);
929 }
930 
931 /**
932  * visu_node_array_removeNodesOfElement:
933  * @nodeArray: a #VisuNodeArray object.
934  * @element: a #VisuElement object.
935  *
936  * Remove all the #VisuNode from the element @element. The properties
937  * are also updated.
938  *
939  * Since: 3.7
940  */
visu_node_array_removeNodesOfElement(VisuNodeArray * nodeArray,VisuElement * element)941 void visu_node_array_removeNodesOfElement(VisuNodeArray *nodeArray, VisuElement *element)
942 {
943   guint i;
944   gint iEle;
945   EleArr *ele;
946   GArray *nodeNumbers;
947   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
948 
949   g_return_if_fail(priv && element);
950 
951   iEle = visu_node_array_getElementId(nodeArray, element);
952   if (iEle < 0)
953     return;
954 
955   /* We keep the allocation to avoid deallocating, reallocating. */
956 
957   /* Begin by removing the the node properties. */
958   g_hash_table_foreach(priv->nodeProp,
959                        removeNodePropertyForElement, GINT_TO_POINTER(iEle));
960 
961   ele = _getEleArr(priv, iEle);
962   if (ele->nStoredNodes == 0)
963     return;
964 
965   /* We update the node table. */
966   nodeNumbers = g_array_new(FALSE, FALSE, sizeof(guint));
967   for (i = 0; i < ele->nStoredNodes; i++)
968     {
969       g_array_append_val(nodeNumbers, ele->nodes[i].number);
970       if (priv->origProp->data_int[ele->nodes[i].posElement][ele->nodes[i].posNode] < 0)
971         priv->nOrigNodes -= 1;
972       _setAtId(&priv->nodeTable, ele->nodes[i].number, (VisuNode*)0);
973     }
974   ele->nStoredNodes = 0;
975   _compactNodeTable(&priv->nodeTable);
976 
977   DBG_fprintf(stderr, "Visu NodeArray: emit a 'NodePopulationDecrease' signal.\n");
978   g_object_notify_by_pspec(G_OBJECT(nodeArray), properties[NNODES_PROP]);
979   g_signal_emit(G_OBJECT(nodeArray), visu_node_array_signals[POPULATION_DECREASE_SIGNAL],
980 		0, (gpointer)nodeNumbers, NULL);
981   g_array_unref(nodeNumbers);
982 }
983 
984 /**
985  * visu_node_array_removeAllDuplicateNodes:
986  * @nodeArray: a #VisuNodeArray object.
987  *
988  * Remove all nodes that are not original in the box.
989  *
990  * Returns: TRUE if some nodes have been removed.
991  */
visu_node_array_removeAllDuplicateNodes(VisuNodeArray * nodeArray)992 gboolean visu_node_array_removeAllDuplicateNodes(VisuNodeArray *nodeArray)
993 {
994   GArray *tmp;
995   guint i, j;
996   EleArr *ele;
997   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
998 
999   g_return_val_if_fail(priv, FALSE);
1000 
1001   tmp = g_array_new(FALSE, FALSE, sizeof(int));
1002   for (i = 0; i < priv->elements->len; i++)
1003     {
1004       ele = _getEleArr(priv, i);
1005       for (j = 0; j < ele->nStoredNodes; j++)
1006         if (priv->origProp->data_int[i][j] >= 0)
1007           tmp = g_array_append_val(tmp, ele->nodes[j].number);
1008     }
1009 
1010   if (tmp->len > 0)
1011     {
1012       visu_node_array_removeNodes(nodeArray, tmp);
1013       g_array_unref(tmp);
1014       return TRUE;
1015     }
1016 
1017   g_array_free(tmp, TRUE);
1018   return FALSE;
1019 }
1020 
1021 /**
1022  * visu_node_array_getFromId:
1023  * @array: a #VisuNodeArray structure which stores the nodes.
1024  * @number: an integer.
1025  *
1026  * This methods retrieves the #VisuNode identified by the integer @number.
1027  * The number must be strictly positive. No error is raised if no node corresponds
1028  * to the given number.
1029  *
1030  * Returns: (transfer none): the found #VisuNode or NULL if none corresponds to number.
1031  */
visu_node_array_getFromId(VisuNodeArray * array,guint number)1032 VisuNode* visu_node_array_getFromId(VisuNodeArray *array, guint number)
1033 {
1034   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1035   g_return_val_if_fail(priv, (VisuNode*)0);
1036 
1037   /* DBG_fprintf(stderr, "Visu NodeArray: get VisuNode from number %d.\n", number); */
1038   if (_validNodeTableId(&priv->nodeTable, number))
1039     return _getFromId(&priv->nodeTable, number);
1040   else
1041     return (VisuNode*)0;
1042 }
1043 
1044 /**
1045  * visu_node_array_getOriginal:
1046  * @nodeArray: a #VisuNodeArray object.
1047  * @nodeId: a node id.
1048  *
1049  * Test if the given @nodeId is an original or a replica for the
1050  * periodisation.
1051  *
1052  * Returns: the original node index or -1 if @nodeId is original.
1053  */
visu_node_array_getOriginal(VisuNodeArray * nodeArray,guint nodeId)1054 gint visu_node_array_getOriginal(VisuNodeArray *nodeArray, guint nodeId)
1055 {
1056   VisuNode *node;
1057   gint orig;
1058   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
1059 
1060   g_return_val_if_fail(priv && priv->origProp, -1);
1061   g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1);
1062 
1063   orig = (gint)nodeId;
1064   do
1065     {
1066       node = _getFromId(&priv->nodeTable, orig);
1067       orig = priv->origProp->data_int[node->posElement][node->posNode];
1068     }
1069   while (orig >= 0);
1070 /*   DBG_fprintf(stderr, "Visu Node: get original from %d: %d (%d).\n", */
1071 /* 	      nodeId, node->number, */
1072 /* 	      nodeArray->priv->origProp->data_int[node->posElement][node->posNode]); */
1073   return (node->number == nodeId)?-1:(gint)node->number;
1074 }
1075 
1076 /**
1077  * visu_node_array_setOriginal:
1078  * @nodeArray: a #VisuNodeArray object.
1079  * @nodeId: a node id.
1080  *
1081  * Make @nodeId an original node.
1082  *
1083  * Returns: TRUE if @nodeId was not original.
1084  */
visu_node_array_setOriginal(VisuNodeArray * nodeArray,guint nodeId)1085 gboolean visu_node_array_setOriginal(VisuNodeArray *nodeArray, guint nodeId)
1086 {
1087   VisuNode *node;
1088   gint orig;
1089   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
1090 
1091   g_return_val_if_fail(priv && priv->origProp, -1);
1092   g_return_val_if_fail(_validNodeTableId(&priv->nodeTable, nodeId), -1);
1093 
1094   node = _getFromId(&priv->nodeTable, nodeId);
1095   g_return_val_if_fail(node, FALSE);
1096 
1097   orig = priv->origProp->data_int[node->posElement][node->posNode];
1098   priv->origProp->data_int[node->posElement][node->posNode] = -1;
1099   if (orig != -1)
1100     priv->nOrigNodes += 1;
1101 
1102   DBG_fprintf(stderr, "Visu Node: set original for %d (%d).\n",
1103 	      nodeId, orig);
1104   return (orig != -1);
1105 }
1106 
1107 /**
1108  * visu_node_array_switchNumber:
1109  * @nodeArray: a #VisuNodeArray object.
1110  * @from: a node id.
1111  * @to: another node id.
1112  *
1113  * Two nodes of @nodeArray switches their number.
1114  *
1115  * Since: 3.6
1116  *
1117  * Returns: TRUE if number is switched.
1118  */
visu_node_array_switchNumber(VisuNodeArray * nodeArray,guint from,guint to)1119 gboolean visu_node_array_switchNumber(VisuNodeArray *nodeArray, guint from, guint to)
1120 {
1121   VisuNode *nodeFrom, *nodeTo;
1122   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
1123 
1124   if (from == to)
1125     return FALSE;
1126 
1127   g_return_val_if_fail(priv, FALSE);
1128   nodeFrom = _getFromId(&priv->nodeTable, from);
1129   nodeTo   = _getFromId(&priv->nodeTable, to);
1130   _setAtId(&priv->nodeTable, from, nodeTo);
1131   _setAtId(&priv->nodeTable, to, nodeFrom);
1132   nodeFrom->number = to;
1133   nodeTo->number   = from;
1134   return TRUE;
1135 }
1136 
1137 /**
1138  * visu_node_array_compareElements:
1139  * @data1: a #VisuData object ;
1140  * @data2: an other #VisuData object.
1141  *
1142  * This method is used to compare the composition of the given two #VisuData objects.
1143  * The test is only done on #VisuElement lists.
1144  *
1145  * Returns: TRUE if the two objects contains exactly the same #VisuElement objects (not
1146  *          one more or one less or one different), FALSE otherwise.
1147  */
visu_node_array_compareElements(VisuNodeArray * data1,VisuNodeArray * data2)1148 gboolean visu_node_array_compareElements(VisuNodeArray *data1, VisuNodeArray *data2)
1149 {
1150   guint i, j;
1151   gboolean found;
1152   VisuNodeArrayPrivate *priv1 = visu_node_array_get_instance_private(data1);
1153   VisuNodeArrayPrivate *priv2 = visu_node_array_get_instance_private(data2);
1154 
1155   g_return_val_if_fail(priv1 && priv2, FALSE);
1156 
1157   DBG_fprintf(stderr, "Visu NodeArray: comparing composition of '%p' and '%p'.\n",
1158 	      (gpointer)data1, (gpointer)data2);
1159   if (data1 == data2)
1160     return TRUE;
1161 
1162   if (priv1->elements->len != priv2->elements->len)
1163     return FALSE;
1164 
1165   for (i = 0; i < priv1->elements->len; i++)
1166     {
1167       found = FALSE;
1168       for (j = 0; !found && j < priv2->elements->len; j++)
1169         found = (_getElement(priv1, i) == _getElement(priv2, j));
1170       if (!found)
1171         return FALSE;
1172     }
1173 
1174   return TRUE;
1175 }
_appendElement(VisuNodeArray * nodeArray,const VisuElement * element)1176 static gint _appendElement(VisuNodeArray *nodeArray, const VisuElement *element)
1177 {
1178   GArray *ele, *nEle;
1179   guint one = 1;
1180   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
1181 
1182   g_return_val_if_fail(VISU_IS_ELEMENT(element), -1);
1183 
1184   ele = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*), 1);
1185   g_array_append_val(ele, element);
1186   nEle = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1);
1187   g_array_append_val(nEle, one);
1188   visu_node_array_allocate(nodeArray, ele, nEle);
1189   g_array_free(ele, TRUE);
1190   g_array_free(nEle, TRUE);
1191 
1192   return priv->elements->len - 1;
1193 }
1194 /**
1195  * visu_node_array_getElement:
1196  * @data: a #VisuNodeArray object ;
1197  * @node: a #VisuNode of this array.
1198  *
1199  * This routine gets the #VisuElement the @node belongs to.
1200  *
1201  * Since: 3.7
1202  *
1203  * Returns: (transfer none): a #VisuElement, owned by V_Sim.
1204  */
visu_node_array_getElement(const VisuNodeArray * data,const VisuNode * node)1205 VisuElement* visu_node_array_getElement(const VisuNodeArray *data, const VisuNode *node)
1206 {
1207   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)data);
1208   g_return_val_if_fail(priv && node, (VisuElement*)0);
1209 
1210   return _getElement(priv, node->posElement);
1211 }
1212 /**
1213  * visu_node_array_setElement:
1214  * @data: a #VisuNodeArray object.
1215  * @node: a #VisuNode pointer.
1216  * @element: a #VisuElement object.
1217  *
1218  * Change the nature of the #VisuElement of @node to be @element.
1219  *
1220  * Since: 3.8
1221  *
1222  * Returns: (transfer none): the new location of the #VisuNode.
1223  **/
visu_node_array_setElement(VisuNodeArray * data,VisuNode * node,const VisuElement * element)1224 VisuNode* visu_node_array_setElement(VisuNodeArray *data, VisuNode *node,
1225                                      const VisuElement *element)
1226 {
1227   VisuNode* out;
1228   gint iEle;
1229   GArray *arr;
1230   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);
1231 
1232   g_return_val_if_fail(priv && node, (VisuNode*)0);
1233 
1234   iEle = visu_node_array_getElementId(data, element);
1235   if ((gint)node->posElement == iEle)
1236     return node;
1237 
1238   if (iEle < 0)
1239     iEle = _appendElement(data, element);
1240   DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n",
1241 	      node->number, iEle, node->posNode);
1242   visu_node_array_startAdding(data);
1243 
1244   out = newOrCopyNode(data, iEle, node->number);
1245   _setAtId(&priv->nodeTable, out->number, (VisuNode*)0);
1246   out->number = node->number;
1247 
1248   arr = g_array_sized_new(FALSE, FALSE, sizeof(guint), 1);
1249   g_array_append_val(arr, node->number);
1250   visu_node_array_removeNodes(data, arr);
1251   g_array_free(arr, TRUE);
1252 
1253   _setAtId(&priv->nodeTable, out->number, out);
1254   priv->origProp->data_int[out->posElement][out->posNode] = -1;
1255   priv->nOrigNodes += 1;
1256 
1257   g_array_insert_val(priv->nodeTable.popIncIds, 0, out->number);
1258   visu_node_array_completeAdding(data);
1259 
1260   DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number);
1261   return out;
1262 
1263 }
1264 /**
1265  * visu_node_array_containsElement:
1266  * @array: a #VisuNodeArray object.
1267  * @element: a #VisuElement object.
1268  *
1269  * Tests if @element is contained in @array. @element may be part of
1270  * @array but without nodes.
1271  *
1272  * Since: 3.8
1273  *
1274  * Returns: TRUE, if @array contains @element.
1275  **/
visu_node_array_containsElement(const VisuNodeArray * array,const VisuElement * element)1276 gboolean visu_node_array_containsElement(const VisuNodeArray *array,
1277                                          const VisuElement *element)
1278 {
1279   guint i;
1280   const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
1281 
1282   g_return_val_if_fail(priv, FALSE);
1283 
1284   for (i = 0; i < priv->elements->len; i++)
1285     if (_getElement(priv, i) == element)
1286       return TRUE;
1287   return FALSE;
1288 }
1289 /**
1290  * visu_node_array_getElementId:
1291  * @array: a #VisuNodeArray object ;
1292  * @element: a #VisuElement object.
1293  *
1294  * This routines returns the internal id used to represent @element,
1295  * or -1 if not found.
1296  *
1297  * Since: 3.7
1298  *
1299  * Returns: a positive number or -1 if not found.
1300  */
visu_node_array_getElementId(const VisuNodeArray * array,const VisuElement * element)1301 gint visu_node_array_getElementId(const VisuNodeArray *array, const VisuElement *element)
1302 {
1303   guint i;
1304   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
1305 
1306   g_return_val_if_fail(priv, -1);
1307 
1308   for (i = 0; i < priv->elements->len; i++)
1309     if (_getElement(priv, i) == element)
1310       return i;
1311   return -1;
1312 }
1313 /**
1314  * visu_node_array_getNNodes:
1315  * @array: a #VisuNodeArray object.
1316  *
1317  * This routines returns the number of #VisuNode stored in @array.
1318  *
1319  * Since: 3.7
1320  *
1321  * Returns: a positive number.
1322  */
visu_node_array_getNNodes(const VisuNodeArray * array)1323 guint visu_node_array_getNNodes(const VisuNodeArray *array)
1324 {
1325   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
1326   g_return_val_if_fail(priv, 0);
1327 
1328   return priv->nodeTable.nStoredNodes;
1329 }
1330 /**
1331  * visu_node_array_getNOriginalNodes:
1332  * @array: a #VisuNodeArray object.
1333  *
1334  * This routines returns the number of original #VisuNode stored in @array.
1335  *
1336  * Since: 3.7
1337  *
1338  * Returns: a positive number.
1339  */
visu_node_array_getNOriginalNodes(const VisuNodeArray * array)1340 guint visu_node_array_getNOriginalNodes(const VisuNodeArray *array)
1341 {
1342   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
1343   g_return_val_if_fail(priv, 0);
1344 
1345   return priv->nOrigNodes;
1346 }
1347 /**
1348  * visu_node_array_getNElements:
1349  * @array: a #VisuNodeArray object ;
1350  * @physical: a boolean.
1351  *
1352  * The parameter @array stores several #VisuNode of #VisuElement. This
1353  * routine is used to get the number of #VisuElement that are used by
1354  * this @array. Depending on @physical value, the number of
1355  * #VisuElement representing physical element or not is retrieved. The
1356  * actual returned number of #VisuElement take into account only
1357  * elements with a positive number of nodes.
1358  *
1359  * Since: 3.7
1360  *
1361  * Returns: a positive number.
1362  */
visu_node_array_getNElements(const VisuNodeArray * array,gboolean physical)1363 guint visu_node_array_getNElements(const VisuNodeArray *array, gboolean physical)
1364 {
1365   guint nEle, i;
1366   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)array);
1367 
1368   g_return_val_if_fail(priv, 0);
1369 
1370   nEle = 0;
1371   for (i = 0; i < priv->elements->len; i++)
1372     if (_getEleArr(priv, i)->nStoredNodes > 0)
1373       {
1374         if (physical && visu_element_getPhysical(_getElement(priv, i)))
1375           nEle += 1;
1376         else if (!physical)
1377           nEle += 1;
1378       }
1379 
1380   return nEle;
1381 }
1382 
1383 /**
1384  * visu_node_array_allocateNodesForElement:
1385  * @array: a #VisuNodeArray object ;
1386  * @eleId: an internal #VisuElement id ;
1387  * @nNodes: a positive number of nodes.
1388  *
1389  * This routine is used to allocate space for @nNodes of a
1390  * #VisuElement. This #VisuElement is identified by its internal id,
1391  * see visu_node_array_getElementId(). If this #VisuElement has
1392  * already enough space in this @array, nothing is done, otherwise
1393  * space is reallocated.
1394  *
1395  * Since: 3.7
1396  */
visu_node_array_allocateNodesForElement(VisuNodeArray * array,guint eleId,guint nNodes)1397 void visu_node_array_allocateNodesForElement(VisuNodeArray *array, guint eleId, guint nNodes)
1398 {
1399   guint j, delta;
1400   VisuNode *oldNodeList;
1401   EleArr *ele;
1402   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1403 
1404   g_return_if_fail(priv && eleId < priv->elements->len);
1405 
1406   ele = _getEleArr(priv, eleId);
1407   if (ele->nNodes >= nNodes)
1408     return;
1409 
1410   delta = nNodes - ele->nNodes;
1411   oldNodeList = ele->nodes;
1412   DBG_fprintf(stderr, "Visu Node: reallocation needed for element "
1413 	      "%d with %d nodes.\n", eleId, delta);
1414   ele->nNodes = nNodes;
1415   ele->nodes  = g_realloc(ele->nodes, sizeof(VisuNode) * ele->nNodes);
1416   _increaseNodeTable(&priv->nodeTable, delta);
1417   DBG_fprintf(stderr, " | (all)%d/%d # (%d)%d/%d\n",
1418 	      priv->nodeTable.nStoredNodes, priv->nodeTable.nNodes,
1419               eleId, ele->nStoredNodes, ele->nNodes);
1420   /* We set the default values for the new nodes. */
1421   for (j = ele->nStoredNodes; j < ele->nNodes; j++)
1422     {
1423       ele->nodes[j].posElement = eleId;
1424       ele->nodes[j].posNode    = j;
1425     }
1426   /* If the node list has been moved, we need to reassign pointers
1427      of array nodeTable. */
1428   if (oldNodeList != ele->nodes)
1429     for (j = 0; j < ele->nStoredNodes; j++)
1430       _setAtId(&priv->nodeTable, ele->nodes[j].number, ele->nodes + j);
1431   /* We reallocate the table properties. */
1432   g_hash_table_foreach(priv->nodeProp, reallocNodeProperty,
1433 		       GINT_TO_POINTER(eleId));
1434 
1435   /* Test part for the nodeTable array. */
1436 #if DEBUG == 1
1437   _checkNodeTable(&priv->nodeTable);
1438 #endif
1439   DBG_fprintf(stderr, "Visu Node: reallocation OK.\n");
1440   DBG_fprintf(stderr, " | size = %do\n",
1441 	      (int)(priv->elements->len * sizeof(EleArr) + sizeof(GArray) +
1442                     sizeof(VisuNode) * priv->nodeTable.nNodes +
1443 		    sizeof(VisuNode*) * priv->nodeTable.nNodes + sizeof(VisuNodeArray)));
1444 }
1445 
1446 /**
1447  * visu_node_array_getNewNode:
1448  * @nodeArray: a #VisuNodeArray object ;
1449  * @element: a #VisuElement object.
1450  *
1451  * Return the location of an unstored node for the given #VisuElement.
1452  * The returned node is then added in the list of used nodes.
1453  *
1454  * Since: 3.8
1455  *
1456  * Returns: (transfer none): the location of a newly used node.
1457  */
visu_node_array_getNewNode(VisuNodeArray * nodeArray,const VisuElement * element)1458 VisuNode* visu_node_array_getNewNode(VisuNodeArray *nodeArray, const VisuElement *element)
1459 {
1460   gint iEle;
1461 
1462   iEle = visu_node_array_getElementId(nodeArray, element);
1463   if (iEle < 0)
1464     iEle = _appendElement(nodeArray, element);
1465   DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle);
1466   return newOrCopyNode(nodeArray, iEle, -1);
1467 }
1468 
1469 /**
1470  * visu_node_array_getNewNodeForId:
1471  * @nodeArray: a #VisuNodeArray object ;
1472  * @iEle: the id used in @nodeArray to index a #VisuElement.
1473  *
1474  * Return the location of an unstored node for the given #VisuElement.
1475  * The returned node is then added in the list of used nodes.
1476  *
1477  * Returns: (transfer none): the location of a newly used node.
1478  */
visu_node_array_getNewNodeForId(VisuNodeArray * nodeArray,guint iEle)1479 VisuNode* visu_node_array_getNewNodeForId(VisuNodeArray *nodeArray, guint iEle)
1480 {
1481   DBG_fprintf(stderr, "Visu Node: create a new node of element %d.\n", iEle);
1482   return newOrCopyNode(nodeArray, iEle, -1);
1483 }
1484 
1485 /**
1486  * visu_node_array_copyNode:
1487  * @nodeArray: a #VisuNodeArray object ;
1488  * @node: a node of the given #VisuNodeArray.
1489  *
1490  * Return the location of an unstored node that is the deep copy of the given node.
1491  * The returned node is then added in the list of used nodes.
1492  *
1493  * Returns: (transfer none): the location of a newly used node.
1494  */
visu_node_array_copyNode(VisuNodeArray * nodeArray,VisuNode * node)1495 VisuNode* visu_node_array_copyNode(VisuNodeArray *nodeArray, VisuNode *node)
1496 {
1497   VisuNode* out;
1498 
1499   DBG_fprintf(stderr, "Visu Node: copy a new node from node %d (%d-%d).\n",
1500 	      node->number, node->posElement, node->posNode);
1501   out = newOrCopyNode(nodeArray, node->posElement, node->number);
1502   DBG_fprintf(stderr, "Visu Node: copy a new node from node -> %d.\n", out->number);
1503   return out;
1504 }
_emitPopInc(gpointer data)1505 static gboolean _emitPopInc(gpointer data)
1506 {
1507   visu_node_array_completeAdding(VISU_NODE_ARRAY(data));
1508   g_object_unref(G_OBJECT(data));
1509   return FALSE;
1510 }
newOrCopyNode(VisuNodeArray * nodeArray,int iEle,int oldNodeId)1511 static VisuNode* newOrCopyNode(VisuNodeArray *nodeArray, int iEle,
1512 			       int oldNodeId)
1513 {
1514   EleArr *ele;
1515   VisuNode *node, *oldNode;
1516   struct twoNodes nodes;
1517   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
1518 
1519   g_return_val_if_fail(priv, (VisuNode*)0);
1520   g_return_val_if_fail((oldNodeId >= 0 &&
1521                         _validNodeTableId(&priv->nodeTable, (guint)oldNodeId)) ||
1522 		       (iEle >= 0 && iEle < (int)priv->elements->len),
1523 		       (VisuNode*)0);
1524 
1525   ele = _getEleArr(priv, iEle);
1526   if (ele->nStoredNodes == ele->nNodes)
1527     /* We need to realloc... */
1528     visu_node_array_allocateNodesForElement(nodeArray, iEle,
1529                                             ele->nNodes + REALLOCATION_STEP);
1530 
1531   /* Get the new node. */
1532   node = ele->nodes + ele->nStoredNodes;
1533   _addNodeTable(&priv->nodeTable, node);
1534   /* Update the node internal values. */
1535   ele->nStoredNodes += 1;
1536 
1537   /* Set default values. */
1538   node->xyz[0] = 0.f;
1539   node->xyz[1] = 0.f;
1540   node->xyz[2] = 0.f;
1541   node->translation[0] = 0.f;
1542   node->translation[1] = 0.f;
1543   node->translation[2] = 0.f;
1544   node->rendered = FALSE;
1545 
1546   /* We copy the values from oldNode. */
1547   oldNode = (VisuNode*)0;
1548   if (oldNodeId >= 0 && (oldNode = _getFromId(&priv->nodeTable, oldNodeId)))
1549     {
1550       node->xyz[0]         = oldNode->xyz[0];
1551       node->xyz[1]         = oldNode->xyz[1];
1552       node->xyz[2]         = oldNode->xyz[2];
1553       node->translation[0] = oldNode->translation[0];
1554       node->translation[1] = oldNode->translation[1];
1555       node->translation[2] = oldNode->translation[2];
1556       node->rendered       = oldNode->rendered;
1557     }
1558 
1559   /* Create new properties for the node. */
1560   nodes.newNode = node;
1561   nodes.oldNode = oldNode;
1562   g_hash_table_foreach(priv->nodeProp, createNodeproperty, (gpointer)&nodes);
1563 
1564   /* If we have an old node, we use it as original node id, or we put
1565      -1 if not. */
1566   priv->origProp->data_int[node->posElement][node->posNode] = oldNodeId;
1567   if (oldNodeId < 0)
1568     priv->nOrigNodes += 1;
1569 
1570   if (!priv->nodeTable.popIncIds)
1571     {
1572       visu_node_array_startAdding(nodeArray);
1573       g_array_append_val(priv->nodeTable.popIncIds, node->number);
1574       g_idle_add(_emitPopInc, g_object_ref(nodeArray));
1575     }
1576   else
1577     {
1578       g_array_append_val(priv->nodeTable.popIncIds, node->number);
1579     }
1580 
1581   return node;
1582 }
1583 /**
1584  * visu_node_array_startAdding:
1585  * @array: a #VisuNodeArray object.
1586  *
1587  * Begin to accumulate the node ids that are added to the
1588  * structure. When addition is finished, call
1589  * visu_node_array_completeAdding() to ensure completion and emit signals.
1590  *
1591  * Since: 3.8
1592  **/
visu_node_array_startAdding(VisuNodeArray * array)1593 void visu_node_array_startAdding(VisuNodeArray *array)
1594 {
1595   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1596   g_return_if_fail(priv && !priv->nodeTable.popIncIds);
1597 
1598   priv->nodeTable.popIncIds = g_array_new(FALSE, FALSE, sizeof(guint));
1599 }
1600 /**
1601  * visu_node_array_completeAdding:
1602  * @array: a #VisuNodeArray object.
1603  *
1604  * After new nodes have been added, call this routine to ensure that
1605  * proper signals are emitted. See visu_node_array_startAdding() to
1606  * start a bunch addition of new nodes.
1607  *
1608  * Since: 3.8
1609  **/
visu_node_array_completeAdding(VisuNodeArray * array)1610 void visu_node_array_completeAdding(VisuNodeArray *array)
1611 {
1612   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1613   g_return_if_fail(priv && priv->nodeTable.popIncIds);
1614 
1615   if (priv->nodeTable.popIncIds->len > 0)
1616     {
1617       g_object_notify_by_pspec(G_OBJECT(array), properties[NNODES_PROP]);
1618       DBG_fprintf(stderr, "Visu NodeArray: emit a 'PopulationIncrease' signal.\n");
1619       g_signal_emit(G_OBJECT(array),
1620                     visu_node_array_signals[POPULATION_INCREASE_SIGNAL],
1621                     0, priv->nodeTable.popIncIds, NULL);
1622     }
1623 
1624   g_array_unref(priv->nodeTable.popIncIds);
1625   priv->nodeTable.popIncIds = (GArray*)0;
1626 }
_resetVisibility(VisuMaskable * self)1627 static gboolean _resetVisibility(VisuMaskable *self)
1628 {
1629   gboolean redraw;
1630   guint i, j;
1631   EleArr *ele;
1632   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(VISU_NODE_ARRAY(self));
1633 
1634   g_return_val_if_fail(priv, FALSE);
1635   redraw = FALSE;
1636   for (i = 0; i < priv->elements->len; i++)
1637     for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
1638       redraw = visu_node_setVisibility(ele->nodes + j, TRUE) || redraw;
1639   return redraw;
1640 }
_getMasked(const VisuMaskable * self)1641 static GArray* _getMasked(const VisuMaskable *self)
1642 {
1643   GArray *masked;
1644   guint i, j;
1645   EleArr *ele;
1646   const VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private((VisuNodeArray*)self);
1647 
1648   g_return_val_if_fail(priv, FALSE);
1649 
1650   masked = g_array_sized_new(FALSE, FALSE, sizeof(guint), priv->nodeTable.nStoredNodes / 10);
1651   for (i = 0; i < priv->elements->len; i++)
1652     for(ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
1653       if (!visu_node_getVisibility(ele->nodes + j))
1654         g_array_append_val(masked, ele->nodes[j].number);
1655   return masked;
1656 }
1657 /**
1658  * visu_node_array_setNodeVisibility:
1659  * @nodeArray: a #VisuNodeArray object.
1660  * @id: a node id.
1661  * @status: a boolean.
1662  *
1663  * Change the visibility of node @id in @nodeArray. If @id is out of
1664  * bound, nothing is done and no error raised. If visibility is indeed
1665  * changed, then #VisuNodeArray::VisibilityChanged signal is emitted.
1666  *
1667  * Since: 3.8
1668  *
1669  * Returns: TRUE if visibility of node @id is indeed changed.
1670  **/
visu_node_array_setNodeVisibility(VisuNodeArray * nodeArray,guint id,gboolean status)1671 gboolean visu_node_array_setNodeVisibility(VisuNodeArray *nodeArray, guint id,
1672                                            gboolean status)
1673 {
1674   VisuNode *node;
1675 
1676   g_return_val_if_fail(VISU_IS_NODE_ARRAY(nodeArray), FALSE);
1677 
1678   node = visu_node_array_getFromId(nodeArray, id);
1679   if (!node)
1680     return FALSE;
1681 
1682   if (!visu_node_setVisibility(node, status))
1683     return FALSE;
1684 
1685   visu_maskable_visibilityChanged(VISU_MASKABLE(nodeArray));
1686 
1687   return TRUE;
1688 }
1689 /**
1690  * visu_node_array_startMoving:
1691  * @array: a #VisuNodeArray object.
1692  *
1693  * Begin to accumulate the node ids that are moved in the
1694  * structure. When moving is finished, call
1695  * visu_node_array_completeMoving() to ensure completion and emit signals.
1696  *
1697  * Since: 3.8
1698  **/
visu_node_array_startMoving(VisuNodeArray * array)1699 void visu_node_array_startMoving(VisuNodeArray *array)
1700 {
1701   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1702   g_return_if_fail(priv && !priv->nodeTable.posChgIds);
1703 
1704   DBG_fprintf(stderr, "Visu Nodes: starting moving nodes.\n");
1705   priv->nodeTable.posChgIds = g_array_new(FALSE, FALSE, sizeof(guint));
1706 }
1707 /**
1708  * visu_node_array_completeMoving:
1709  * @array: a #VisuNodeArray object.
1710  *
1711  * After new nodes have been moved, call this routine to ensure that
1712  * proper signals are emitted. See visu_node_array_startMoving() to
1713  * start a bunch movements of new nodes.
1714  *
1715  * Since: 3.8
1716  **/
visu_node_array_completeMoving(VisuNodeArray * array)1717 void visu_node_array_completeMoving(VisuNodeArray *array)
1718 {
1719   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1720   g_return_if_fail(priv && priv->nodeTable.posChgIds);
1721 
1722   if (priv->nodeTable.posChgIds->len > 0)
1723     {
1724       DBG_fprintf(stderr, "Visu NodeArray: emit a 'position-changed' signal.\n");
1725       g_signal_emit(G_OBJECT(array),
1726                     visu_node_array_signals[POSITION_CHANGED_SIGNAL],
1727                     0, priv->nodeTable.posChgIds, NULL);
1728     }
1729 
1730   DBG_fprintf(stderr, "Visu Nodes: complete moving nodes.\n");
1731   g_array_unref(priv->nodeTable.posChgIds);
1732   priv->nodeTable.posChgIds = (GArray*)0;
1733 }
_emitPosChg(gpointer data)1734 static gboolean _emitPosChg(gpointer data)
1735 {
1736   visu_node_array_completeMoving(VISU_NODE_ARRAY(data));
1737   g_object_unref(G_OBJECT(data));
1738   return FALSE;
1739 }
1740 /**
1741  * visu_node_array_shiftNode:
1742  * @array: a #VisuNodeArray object.
1743  * @id: a node id.
1744  * @delta: (array fixed-size=3): a shift in cartesian coordinates.
1745  *
1746  * Move the node @id of the quantity @delta given in cartesian
1747  * coordinates. If several nodes should be shifted, consider using
1748  * visu_node_array_shiftNodes() or encapsulate the calls within
1749  * visu_node_array_startMoving() and visu_node_array_completeMoving().
1750  *
1751  * Since: 3.8
1752  **/
visu_node_array_shiftNode(VisuNodeArray * array,guint id,const gfloat delta[3])1753 void visu_node_array_shiftNode(VisuNodeArray *array, guint id, const gfloat delta[3])
1754 {
1755   VisuNode *node;
1756   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1757 
1758   g_return_if_fail(priv);
1759 
1760   node = visu_node_array_getFromId(array, id);
1761   if (node)
1762     {
1763       node->xyz[0] += delta[0];
1764       node->xyz[1] += delta[1];
1765       node->xyz[2] += delta[2];
1766     }
1767   if (!priv->nodeTable.posChgIds)
1768     {
1769       visu_node_array_startMoving(array);
1770       g_array_append_val(priv->nodeTable.posChgIds, node->number);
1771       g_idle_add(_emitPosChg, g_object_ref(array));
1772     }
1773   else
1774     {
1775       g_array_append_val(priv->nodeTable.posChgIds, node->number);
1776     }
1777 }
1778 /**
1779  * visu_node_array_shiftNodes:
1780  * @array: a #VisuNodeArray object.
1781  * @ids: (element-type uint): a set of #VisuNode ids.
1782  * @delta: (array fixed-size=3): a shift in cartesian coordinates.
1783  *
1784  * Apply @delta on the coordinates of every nodes in @ids.
1785  *
1786  * Since: 3.8
1787  **/
visu_node_array_shiftNodes(VisuNodeArray * array,const GArray * ids,const float delta[3])1788 void visu_node_array_shiftNodes(VisuNodeArray *array, const GArray *ids,
1789                                 const float delta[3])
1790 {
1791   guint i;
1792   gboolean inside;
1793   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1794 
1795   g_return_if_fail(priv);
1796 
1797   inside = (priv->nodeTable.posChgIds != (GArray*)0);
1798   if (!inside)
1799     visu_node_array_startMoving(array);
1800   for (i = 0; i < ids->len; i++)
1801     visu_node_array_shiftNode(array, g_array_index(ids, guint, i), delta);
1802   if (!inside)
1803     visu_node_array_completeMoving(array);
1804 }
1805 /**
1806  * visu_node_array_moveNode:
1807  * @array: a #VisuNodeArray object.
1808  * @id: a node id.
1809  * @at: (array fixed-size=3): a position in cartesian coordinates.
1810  *
1811  * Move the node @id at the posityion @at given in cartesian
1812  * coordinates. If several nodes should be moved, consider using
1813  * visu_node_array_moveNodes() or encapsulate the calls within
1814  * visu_node_array_startMoving() and visu_node_array_completeMoving().
1815  *
1816  * Since: 3.8
1817  **/
visu_node_array_moveNode(VisuNodeArray * array,guint id,const float at[3])1818 void visu_node_array_moveNode(VisuNodeArray *array, guint id, const float at[3])
1819 {
1820   VisuNode *node;
1821   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1822 
1823   g_return_if_fail(priv);
1824 
1825   node = visu_node_array_getFromId(array, id);
1826   if (node)
1827     {
1828       node->xyz[0] = at[0];
1829       node->xyz[1] = at[1];
1830       node->xyz[2] = at[2];
1831     }
1832   if (!priv->nodeTable.posChgIds)
1833     {
1834       visu_node_array_startMoving(array);
1835       g_array_append_val(priv->nodeTable.posChgIds, node->number);
1836       g_idle_add(_emitPosChg, g_object_ref(array));
1837     }
1838   else
1839     {
1840       g_array_append_val(priv->nodeTable.posChgIds, node->number);
1841     }
1842 }
1843 /**
1844  * visu_node_array_moveNodes:
1845  * @array: a #VisuNodeArray object.
1846  * @ids: (element-type uint): a set of #VisuNode ids.
1847  * @xyz: (element-type float): a set of cartesian displacements.
1848  *
1849  * Apply translations on all nodes defined by @ids. Displacements are
1850  * read from @xyz which is an array containing as many float triplets
1851  * as nodes in ids.
1852  *
1853  * Since: 3.8
1854  **/
visu_node_array_moveNodes(VisuNodeArray * array,const GArray * ids,const GArray * xyz)1855 void visu_node_array_moveNodes(VisuNodeArray *array, const GArray *ids,
1856                                const GArray *xyz)
1857 {
1858   guint i;
1859   gboolean inside;
1860   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1861 
1862   g_return_if_fail(priv && ids && xyz && ids->len * 3 == xyz->len);
1863 
1864   inside = (priv->nodeTable.posChgIds != (GArray*)0);
1865   if (!inside)
1866     visu_node_array_startMoving(array);
1867   for (i = 0; i < ids->len; i++)
1868     visu_node_array_moveNode(array, g_array_index(ids, guint, i),
1869                              &g_array_index(xyz, float, 3 * i));
1870   if (!inside)
1871     visu_node_array_completeMoving(array);
1872 }
1873 /**
1874  * visu_node_array_rotateNodes:
1875  * @array: a #VisuNodeArray object.
1876  * @ids: (element-type uint): a set of #VisuNode ids.
1877  * @axis: (array fixed-size=3): an axis orientation.
1878  * @center: (array fixed-size=3): point coordinates.
1879  * @angle: an angle in degrees.
1880  *
1881  * Apply the rotation defined by @angle along @axis passing by @center
1882  * to all nodes referenced in @ids.
1883  *
1884  * Since: 3.8
1885  **/
visu_node_array_rotateNodes(VisuNodeArray * array,const GArray * ids,const float axis[3],const float center[3],float angle)1886 void visu_node_array_rotateNodes(VisuNodeArray *array, const GArray *ids,
1887                                  const float axis[3], const float center[3],
1888                                  float angle)
1889 {
1890   VisuNode *node;
1891   guint i;
1892   float sph[3], mat[3][3], work[3];
1893   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1894 
1895   g_return_if_fail(priv);
1896   g_return_if_fail(axis[0] != 0.f || axis[1] != 0.f || axis[2] != 0.f);
1897 
1898   tool_matrix_cartesianToSpherical(sph, axis);
1899   DBG_fprintf(stderr, "Visu Nodes: rotation along %g %g.\n",
1900               sph[TOOL_MATRIX_SPHERICAL_THETA], sph[TOOL_MATRIX_SPHERICAL_PHI]);
1901   tool_matrix_setIdentity(mat);
1902   tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z);
1903   tool_matrix_rotate(mat, -sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y);
1904   tool_matrix_rotate(mat, angle, TOOL_XYZ_Z);
1905   tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_THETA], TOOL_XYZ_Y);
1906   tool_matrix_rotate(mat, sph[TOOL_MATRIX_SPHERICAL_PHI], TOOL_XYZ_Z);
1907 
1908   for (i = 0; i < ids->len; i++)
1909     {
1910       node = visu_node_array_getFromId(array, g_array_index(ids, guint, i));
1911       if (node)
1912         {
1913           node->xyz[0] -= center[0];
1914           node->xyz[1] -= center[1];
1915           node->xyz[2] -= center[2];
1916           tool_matrix_productVector(work, mat, node->xyz);
1917           node->xyz[0] = work[0] + center[0];
1918           node->xyz[1] = work[1] + center[1];
1919           node->xyz[2] = work[2] + center[2];
1920         }
1921     }
1922   if (priv->nodeTable.posChgIds)
1923     g_array_append_vals(priv->nodeTable.posChgIds, ids->data, ids->len);
1924   else
1925     g_signal_emit(array, visu_node_array_signals[POSITION_CHANGED_SIGNAL], 0, ids);
1926 }
1927 /**
1928  * visu_node_array_join:
1929  * @array: a #VisuNodeArray object.
1930  * @frag: another #VisuNodeArray object.
1931  * @at: (array fixed-size=3): a position in cartesian coordinates.
1932  *
1933  * Add all nodes from @frag to @array and position them centred at @at.
1934  *
1935  * Since: 3.8
1936  *
1937  * Returns: (transfer full) (element-type guint): the ids of the added
1938  * nodes in @array.
1939  **/
visu_node_array_join(VisuNodeArray * array,const VisuNodeArray * frag,const gfloat at[3])1940 GArray* visu_node_array_join(VisuNodeArray *array,
1941                           const VisuNodeArray *frag, const gfloat at[3])
1942 {
1943   GArray *ids;
1944   guint i;
1945   GArray *elements, *nElements;
1946   VisuNodeArrayIter iter;
1947   gfloat centre[3], xyz[3];
1948   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
1949   VisuNodeArrayPrivate *fpriv = visu_node_array_get_instance_private((VisuNodeArray*)frag);
1950 
1951   g_return_val_if_fail(priv && fpriv, NULL);
1952 
1953   elements = g_array_sized_new(FALSE, FALSE, sizeof(VisuElement*),
1954                                fpriv->elements->len);
1955   nElements = g_array_sized_new(FALSE, FALSE, sizeof(guint),
1956                                 fpriv->elements->len);
1957   for (i = 0; i < fpriv->elements->len; i++)
1958     {
1959       EleArr *ele = _getEleArr(fpriv, i);;
1960       g_array_append_val(elements, ele->ele);
1961       g_array_append_val(nElements, ele->nStoredNodes);
1962     }
1963   visu_node_array_allocate(array, elements, nElements);
1964   g_array_unref(elements);
1965   g_array_unref(nElements);
1966 
1967   visu_node_array_iter_new(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter);
1968   centre[0] = 0.f;
1969   centre[1] = 0.f;
1970   centre[2] = 0.f;
1971   for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node;
1972        visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter))
1973     {
1974       centre[0] += iter.node->xyz[0];
1975       centre[1] += iter.node->xyz[1];
1976       centre[2] += iter.node->xyz[2];
1977     }
1978   centre[0] = at[0] - centre[0] / (float)fpriv->nodeTable.nStoredNodes;
1979   centre[1] = at[1] - centre[1] / (float)fpriv->nodeTable.nStoredNodes;
1980   centre[2] = at[2] - centre[2] / (float)fpriv->nodeTable.nStoredNodes;
1981 
1982   visu_node_array_startAdding(array);
1983   for (visu_node_array_iterStart(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter); iter.node;
1984        visu_node_array_iterNext(VISU_NODE_ARRAY((VisuNodeArray*)frag), &iter))
1985     {
1986       VisuNode *node = visu_node_array_getNewNode(array, iter.element);
1987       if (node)
1988         {
1989           xyz[0] = iter.node->xyz[0] + centre[0];
1990           xyz[1] = iter.node->xyz[1] + centre[1];
1991           xyz[2] = iter.node->xyz[2] + centre[2];
1992           visu_node_setCoordinates(node, xyz);
1993         }
1994     }
1995   ids = g_array_ref(priv->nodeTable.popIncIds);
1996   visu_node_array_completeAdding(array);
1997 
1998   return ids;
1999 }
2000 
2001 /*******************/
2002 /* Local routines. */
2003 /*******************/
onElementRenderChanged(VisuNodeArray * data,GParamSpec * pspec _U_,VisuElement * element)2004 static void onElementRenderChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element)
2005 {
2006   DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementVisibilityChanged' signal,"
2007 	      " emitting node render signal.\n");
2008   g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_VISIBILITY_CHANGED_SIGNAL],
2009 		0, element);
2010   visu_maskable_visibilityChanged(VISU_MASKABLE(data));
2011 }
onElementPlaneChanged(VisuNodeArray * data,GParamSpec * pspec _U_,VisuElement * element)2012 static void onElementPlaneChanged(VisuNodeArray *data, GParamSpec *pspec _U_, VisuElement *element)
2013 {
2014   DBG_fprintf(stderr, "Visu NodeArray: caught the 'ElementMaskableChanged' signal,"
2015 	      " emitting node render signal.\n");
2016   g_signal_emit(G_OBJECT(data), visu_node_array_signals[ELEMENT_PLANE_CHANGED_SIGNAL],
2017 		0, element);
2018 }
2019 
2020 
2021 
2022 /**************************/
2023 /* The property routines. */
2024 /**************************/
freeNodePropStruct(gpointer data)2025 static void freeNodePropStruct(gpointer data)
2026 {
2027   VisuNodeProperty *prop;
2028   guint i, j;
2029   EleArr *ele;
2030   VisuNodeArrayPrivate *priv;
2031 
2032   prop = (VisuNodeProperty*)data;
2033   DBG_fprintf(stderr, "Visu Node: freeing node property '%s'.\n", prop->name);
2034 
2035   g_free(prop->name);
2036   priv = visu_node_array_get_instance_private(prop->array);
2037   /* The pointer case. */
2038   if (priv && prop->data_pointer)
2039     {
2040       for (i = 0; i < priv->elements->len; i++)
2041 	{
2042 	  for (ele = _getEleArr(priv, i), j = 0; j < ele->nNodes; j++)
2043             if (prop->data_pointer[i][j])
2044               {
2045                 if (prop->freeTokenFunc)
2046                   prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data);
2047                 else
2048                   g_free(prop->data_pointer[i][j]);
2049               }
2050 	  g_free(prop->data_pointer[i]);
2051 	}
2052       g_free(prop->data_pointer);
2053     }
2054   /* The integer case */
2055   if (priv && prop->data_int)
2056     {
2057       for (i = 0; i < priv->elements->len; i++)
2058 	g_free(prop->data_int[i]);
2059       g_free(prop->data_int);
2060     }
2061   g_free(prop);
2062   DBG_fprintf(stderr, "Visu Node: freeing property ... OK.\n");
2063 }
2064 
2065 /* Remove the property of all nodes of the element given in data. */
removeNodePropertyForElement(gpointer key,gpointer value,gpointer data)2066 static void removeNodePropertyForElement(gpointer key, gpointer value, gpointer data)
2067 {
2068   guint iEle;
2069   guint j;
2070   EleArr *ele;
2071   VisuNodeProperty *prop;
2072   VisuNodeArrayPrivate *priv;
2073 
2074   prop = (VisuNodeProperty*)value;
2075   iEle= GPOINTER_TO_INT(data);
2076   priv = visu_node_array_get_instance_private(prop->array);
2077   g_return_if_fail(priv && iEle < priv->elements->len);
2078   ele = _getEleArr(priv, iEle);
2079 
2080   DBG_fprintf(stderr, "Visu Node: remove node property '%s' for all nodes of element '%s'.\n",
2081 	      (gchar*)key, ele->ele->name);
2082   /* We first remove the property tokens. */
2083   switch (prop->gtype)
2084     {
2085     case G_TYPE_POINTER:
2086       for (j = 0; j < ele->nNodes; j++)
2087         if (prop->data_pointer[iEle][j])
2088           {
2089             if (prop->freeTokenFunc)
2090               prop->freeTokenFunc(prop->data_pointer[iEle][j], prop->user_data);
2091             else
2092               g_free(prop->data_pointer[iEle][j]);
2093             prop->data_pointer[iEle][j] = (gpointer)0;
2094           }
2095       break;
2096     case G_TYPE_INT:
2097       for (j = 0; j < ele->nNodes; j++)
2098         prop->data_int[iEle][j] = 0;
2099       break;
2100     default:
2101       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2102     }
2103 }
2104 
2105 /* Remove the property of the node given in data and move the
2106    last property of this element at the place of the removed node. */
removeNodeProperty(gpointer key,gpointer value,gpointer data)2107 static void removeNodeProperty(gpointer key, gpointer value, gpointer data)
2108 {
2109   EleArr *ele;
2110   VisuNode *node;
2111   VisuNodeProperty *prop;
2112   VisuNodeArrayPrivate *priv;
2113 
2114   node = (VisuNode*)data;
2115   prop = (VisuNodeProperty*)value;
2116   priv = visu_node_array_get_instance_private(prop->array);
2117   g_return_if_fail(priv);
2118   ele = _getEleArr(priv, node->posElement);
2119   g_return_if_fail(ele->nStoredNodes > 0);
2120 
2121   DBG_fprintf(stderr, "Visu Node: remove node property '%s' from %d %d.\n",
2122 	      (gchar*)key, node->posElement, node->posNode);
2123   /* We first remove the property token. */
2124   switch (prop->gtype)
2125     {
2126     case G_TYPE_POINTER:
2127       if (prop->data_pointer[node->posElement][node->posNode])
2128         {
2129           if (prop->freeTokenFunc)
2130             prop->freeTokenFunc(prop->data_pointer[node->posElement][node->posNode],
2131                                 prop->user_data);
2132           else
2133             g_free(prop->data_pointer[node->posElement][node->posNode]);
2134         }
2135       break;
2136     case G_TYPE_INT:
2137       prop->data_int[node->posElement][node->posNode] = 0;
2138       break;
2139     default:
2140       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2141     }
2142 
2143   /* Then we copy the pointer from the last position to the given one.
2144      The last position is given by nStoredNodesPerEle since this counter
2145      has already been lowered. */
2146   switch (prop->gtype)
2147     {
2148     case G_TYPE_POINTER:
2149       prop->data_pointer[node->posElement][node->posNode] =
2150 	prop->data_pointer[node->posElement][ele->nStoredNodes];
2151       prop->data_pointer[node->posElement][ele->nStoredNodes] = (gpointer)0;
2152       break;
2153     case G_TYPE_INT:
2154       prop->data_int[node->posElement][node->posNode] =
2155 	prop->data_int[node->posElement][ele->nStoredNodes];
2156       prop->data_int[node->posElement][ele->nStoredNodes] = 0;
2157       break;
2158     default:
2159       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2160     }
2161 }
2162 
reallocNodeProperty(gpointer key,gpointer value,gpointer data)2163 static void reallocNodeProperty(gpointer key, gpointer value, gpointer data)
2164 {
2165   EleArr *ele;
2166   VisuNodeProperty *prop;
2167   guint iEle, j;
2168   VisuNodeArrayPrivate *priv;
2169 
2170   iEle = (guint)GPOINTER_TO_INT(data);
2171   prop = (VisuNodeProperty*)value;
2172   DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for element %d.\n",
2173 	      (gchar*)key, iEle);
2174 
2175   priv = visu_node_array_get_instance_private(prop->array);
2176   g_return_if_fail(priv && iEle < priv->elements->len);
2177 
2178   ele = _getEleArr(priv, iEle);
2179   switch (prop->gtype)
2180     {
2181     case G_TYPE_POINTER:
2182       prop->data_pointer[iEle] = g_realloc(prop->data_pointer[iEle],
2183 					   sizeof(gpointer) * ele->nNodes);
2184       /* We nullify the newly created properties. */
2185       for (j = ele->nStoredNodes; j < ele->nNodes; j++)
2186 	prop->data_pointer[iEle][j] = (gpointer)0;
2187       break;
2188     case G_TYPE_INT:
2189       prop->data_int[iEle] = g_realloc(prop->data_int[iEle],
2190 				       sizeof(int) * ele->nNodes);
2191       /* We nullify the newly created properties. */
2192       for (j = ele->nStoredNodes; j < ele->nNodes; j++)
2193 	prop->data_int[iEle][j] = 0;
2194       break;
2195     default:
2196       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2197     }
2198 }
2199 
allocateNodeProp(gpointer key,gpointer value,gpointer data _U_)2200 static void allocateNodeProp(gpointer key, gpointer value, gpointer data _U_)
2201 {
2202   guint i;
2203   VisuNodeProperty *prop;
2204   VisuNodeArrayPrivate *priv;
2205 
2206   prop = (VisuNodeProperty*)value;
2207   DBG_fprintf(stderr, "Visu Node: realloc node property '%s' for 1 new element.\n",
2208 	      (gchar*)key);
2209 
2210   priv = visu_node_array_get_instance_private(prop->array);
2211   g_return_if_fail(priv);
2212   switch (prop->gtype)
2213     {
2214     case G_TYPE_POINTER:
2215       prop->data_pointer =
2216         g_realloc(prop->data_pointer, sizeof(gpointer*) * priv->elements->len);
2217       i = priv->elements->len - 1;
2218       prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * _getEleArr(priv, i)->nNodes);
2219       break;
2220     case G_TYPE_INT:
2221       prop->data_int =
2222         g_realloc(prop->data_int, sizeof(int*) * priv->elements->len);
2223       i = priv->elements->len - 1;
2224       prop->data_int[i] = g_malloc0(sizeof(int) * _getEleArr(priv, i)->nNodes);
2225       break;
2226     default:
2227       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2228     }
2229 }
2230 
createNodeproperty(gpointer key,gpointer value,gpointer data)2231 static void createNodeproperty(gpointer key, gpointer value, gpointer data)
2232 {
2233   VisuNodeProperty *prop;
2234   struct twoNodes *nodes;
2235 
2236   prop = (VisuNodeProperty*)value;
2237   nodes = (struct twoNodes*)data;
2238   DBG_fprintf(stderr, "Visu Node: create/copy node property '%s' for node %d-%d.\n",
2239 	      (gchar*)key, nodes->newNode->posElement, nodes->newNode->posNode);
2240 
2241   switch (prop->gtype)
2242     {
2243     case G_TYPE_POINTER:
2244       if (nodes->oldNode)
2245 	prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] =
2246 	  prop->newOrCopyTokenFunc((gconstpointer)prop->data_pointer[nodes->oldNode->posElement][nodes->oldNode->posNode], prop->user_data);
2247       else
2248 	prop->data_pointer[nodes->newNode->posElement][nodes->newNode->posNode] =
2249           (gpointer)0;
2250       break;
2251     case G_TYPE_INT:
2252       if (nodes->oldNode)
2253 	prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] =
2254 	  prop->data_int[nodes->oldNode->posElement][nodes->oldNode->posNode];
2255       else
2256 	prop->data_int[nodes->newNode->posElement][nodes->newNode->posNode] = 0;
2257       break;
2258     default:
2259       g_warning("Unsupported GValue type for property '%s'.", prop->name);
2260     }
2261 }
2262 /*****************************/
2263 /* Public property routines. */
2264 /*****************************/
2265 
2266 /**
2267  * visu_node_property_getArray:
2268  * @nodeProp: a #VisuNodeProperty structure.
2269  *
2270  * Retrieve the #VisuNodeArray @nodeProp is attached to.
2271  *
2272  * Since: 3.8
2273  *
2274  * Returns: (transfer none): the #VisuNodeArray @nodeProp is attached to.
2275  **/
visu_node_property_getArray(const VisuNodeProperty * nodeProp)2276 VisuNodeArray* visu_node_property_getArray(const VisuNodeProperty* nodeProp)
2277 {
2278   g_return_val_if_fail(nodeProp, (VisuNodeArray*)0);
2279   return nodeProp->array;
2280 }
2281 /**
2282  * visu_node_property_setValue:
2283  * @nodeProp: a #VisuNodeProperty object ;
2284  * @node: a #VisuNode object ;
2285  * @value: A GValue pointer this the value to be stored.
2286  *
2287  * This method is used to store some values associated with
2288  * the given @node of the given @nodeArray. These values can be pointers to
2289  * anything allocated (will be free automatically when the property is deleted) or
2290  * they can be static values. This depends on the construction of the node property.
2291  * These values can be retrieved with the visu_node_property_getValue() method.
2292  *
2293  * See visu_node_array_getProperty() to get a property by its name.
2294  */
visu_node_property_setValue(VisuNodeProperty * nodeProp,const VisuNode * node,const GValue * value)2295 void visu_node_property_setValue(VisuNodeProperty* nodeProp,
2296                                  const VisuNode* node, const GValue *value)
2297 {
2298   float fval;
2299   VisuNodeArrayPrivate *priv;
2300 
2301   g_return_if_fail(nodeProp && value);
2302   priv = visu_node_array_get_instance_private(nodeProp->array);
2303   g_return_if_fail(priv && node && node->posElement < priv->elements->len &&
2304 		   node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes);
2305 
2306   switch (nodeProp->gtype)
2307     {
2308     case G_TYPE_POINTER:
2309       /* Quick return if in place. */
2310       if (G_VALUE_HOLDS_BOXED(value) && g_value_get_boxed(value) ==
2311           nodeProp->data_pointer[node->posElement][node->posNode])
2312         return;
2313       if (G_VALUE_HOLDS_POINTER(value) && g_value_get_pointer(value) ==
2314           nodeProp->data_pointer[node->posElement][node->posNode])
2315         return;
2316       /* We free previous pointer. */
2317       if (nodeProp->freeTokenFunc && nodeProp->data_pointer[node->posElement][node->posNode])
2318 	nodeProp->freeTokenFunc(nodeProp->data_pointer[node->posElement][node->posNode],
2319 				nodeProp->user_data);
2320       else
2321 	g_free(nodeProp->data_pointer[node->posElement][node->posNode]);
2322       /* We set the value. */
2323       if (G_VALUE_HOLDS_STRING(value))
2324         nodeProp->data_pointer[node->posElement][node->posNode] =
2325           nodeProp->newOrCopyTokenFunc((gpointer)g_value_get_string(value), nodeProp->user_data);
2326       else if (G_VALUE_HOLDS_FLOAT(value))
2327         {
2328           fval = g_value_get_float(value);
2329           nodeProp->data_pointer[node->posElement][node->posNode] =
2330             nodeProp->newOrCopyTokenFunc(&fval, nodeProp->user_data);
2331         }
2332       else if (G_VALUE_HOLDS_BOXED(value))
2333         nodeProp->data_pointer[node->posElement][node->posNode] =
2334           nodeProp->newOrCopyTokenFunc(g_value_get_boxed(value), nodeProp->user_data);
2335       else
2336         nodeProp->data_pointer[node->posElement][node->posNode] =
2337           nodeProp->newOrCopyTokenFunc(g_value_get_pointer(value), nodeProp->user_data);
2338       break;
2339     case G_TYPE_INT:
2340       if (G_VALUE_HOLDS_BOOLEAN(value))
2341         nodeProp->data_int[node->posElement][node->posNode] =
2342           (int)g_value_get_boolean(value);
2343       else
2344         nodeProp->data_int[node->posElement][node->posNode] = g_value_get_int(value);
2345       break;
2346     default:
2347       g_warning("Unsupported GValue type for property '%s'.", nodeProp->name);
2348     }
2349 }
2350 
2351 /**
2352  * visu_node_property_getValue:
2353  * @nodeProp: a #VisuNodeArray object ;
2354  * @node: a #VisuNode object ;
2355  * @value: an initialise GValue location.
2356  *
2357  * This method is used to retrieve some data associated to
2358  * the specified @node, stored in the given @data. These return data
2359  * should not be freed after used. The read value is stored in the given
2360  * GValue pointer. This GValue must be of the right type, depending on the
2361  * creation of the #VisuNodeProperty.
2362  *
2363  * Returns: some data associated to the key, stored the given GValue location.
2364  */
visu_node_property_getValue(const VisuNodeProperty * nodeProp,const VisuNode * node,GValue * value)2365 GValue* visu_node_property_getValue(const VisuNodeProperty* nodeProp,
2366                                     const VisuNode* node,
2367                                     GValue *value)
2368 {
2369   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeProp->array);
2370   g_return_val_if_fail(priv, value);
2371   g_return_val_if_fail(nodeProp && value, value);
2372   g_return_val_if_fail(node &&
2373                        node->posElement < priv->elements->len &&
2374 		       node->posNode < _getEleArr(priv, node->posElement)->nStoredNodes, value);
2375 
2376   switch (nodeProp->gtype)
2377     {
2378     case G_TYPE_POINTER:
2379       if (G_VALUE_HOLDS_STRING(value))
2380         g_value_set_string(value, (gchar*)nodeProp->data_pointer[node->posElement][node->posNode]);
2381       else if (G_VALUE_HOLDS_BOXED(value))
2382         g_value_set_static_boxed(value, nodeProp->data_pointer[node->posElement][node->posNode]);
2383       else
2384         {
2385           DBG_fprintf(stderr, "Visu Node: get '%s' for node %d(%d,%d) as pointer %p.\n",
2386                       nodeProp->name, node->number, node->posElement, node->posNode,
2387                       (gpointer)nodeProp->data_pointer[node->posElement][node->posNode]);
2388           g_value_set_pointer(value, nodeProp->data_pointer[node->posElement][node->posNode]);
2389         }
2390       return value;
2391     case G_TYPE_INT:
2392       if (G_VALUE_HOLDS_POINTER(value))
2393         {
2394           DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as pointer %d.\n",
2395                       nodeProp->name, node->number,
2396                       nodeProp->data_int[node->posElement][node->posNode]);
2397           g_value_set_pointer(value, &nodeProp->data_int[node->posElement][node->posNode]);
2398         }
2399       else if (G_VALUE_HOLDS_BOOLEAN(value))
2400         g_value_set_boolean(value, (gboolean)nodeProp->data_int[node->posElement][node->posNode]);
2401       else
2402         {
2403           DBG_fprintf(stderr, "Visu Node: get property '%s' for node %d as integer %d.\n",
2404                       nodeProp->name, node->number,
2405                       nodeProp->data_int[node->posElement][node->posNode]);
2406           g_value_set_int(value, nodeProp->data_int[node->posElement][node->posNode]);
2407         }
2408       return value;
2409       break;
2410     default:
2411       g_warning("Unsupported GValue type for property '%s'.", nodeProp->name);
2412     }
2413   return value;
2414 }
2415 
2416 /**
2417  * visu_node_array_getProperty:
2418  * @nodeArray: a #VisuNodeArray object ;
2419  * @key: a string.
2420  *
2421  * This method is used to retrieve the node property associated to the given @key.
2422  *
2423  * Returns: (transfer none): a #VisuNodeProperty.
2424  */
visu_node_array_getProperty(VisuNodeArray * nodeArray,const char * key)2425 VisuNodeProperty* visu_node_array_getProperty(VisuNodeArray* nodeArray, const char* key)
2426 {
2427   VisuNodeProperty *prop;
2428   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
2429 
2430   g_return_val_if_fail(priv && key, (VisuNodeProperty*)0);
2431 
2432   prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, (gpointer)key);
2433   return prop;
2434 }
2435 
2436 /**
2437  * visu_node_array_freeProperty:
2438  * @nodeArray: a #VisuNodeArray object.
2439  * @key: the name of the property to be removed.
2440  *
2441  * This method free the given property and all associated data.
2442  */
visu_node_array_freeProperty(VisuNodeArray * nodeArray,const char * key)2443 void visu_node_array_freeProperty(VisuNodeArray* nodeArray, const char* key)
2444 {
2445   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
2446   g_return_if_fail(priv && key);
2447 
2448   g_hash_table_remove(priv->nodeProp, key);
2449   DBG_fprintf(stderr, "Visu Node: removing the property called '%s'.\n", key);
2450 }
2451 
2452 /**
2453  * visu_node_array_property_newPointer:
2454  * @nodeArray: a #VisuNodeArray object ;
2455  * @key: a string ;
2456  * @freeFunc: (allow-none) (scope call): a method to free each token (can be NULL).
2457  * @newAndCopyFunc: (scope call): a method to create or copy each token.
2458  * @user_data: (closure): a user defined pointer that will be given to
2459  * the free and copy routine.
2460  *
2461  * This method creates and allocates a new area to store nodes associated data that
2462  * can be retrieve with the @key. These data are pointers on allocated memory
2463  * locations. When the property is removed with the #visu_node_freePropertry (or the
2464  * associated #VisuNodeArray is free) the area is free and @freeFunc is called for
2465  * each token (or g_free() if @freeFunc is NULL).
2466  *
2467  * The method @newAndCopyFunc is used when the number of nodes is increased,
2468  * if the const gpointer of the GCopyFunc is not NULL, then we require a copy,
2469  * if it is NULL, then the routine must create a new token with
2470  * default values.
2471  *
2472  * If the property already exists, it is returned.
2473  *
2474  * Returns: (transfer none): the newly created #VisuNodeProperty
2475  * object or the existing one.
2476  */
visu_node_array_property_newPointer(VisuNodeArray * nodeArray,const char * key,GFunc freeFunc,GCopyFunc newAndCopyFunc,gpointer user_data)2477 VisuNodeProperty* visu_node_array_property_newPointer(VisuNodeArray* nodeArray,
2478 					      const char* key,
2479 					      GFunc freeFunc,
2480 					      GCopyFunc newAndCopyFunc,
2481 					      gpointer user_data)
2482 {
2483   VisuNodeProperty *prop;
2484   EleArr *ele;
2485   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
2486   guint i;
2487 
2488   g_return_val_if_fail(priv && key && newAndCopyFunc, (VisuNodeProperty*)0);
2489 
2490   prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
2491   if (prop)
2492     return prop;
2493 
2494   DBG_fprintf(stderr, "Visu Node: adding a new pointer"
2495 	      " property, called '%s'.\n", key);
2496   prop                = g_malloc(sizeof(VisuNodeProperty));
2497   prop->gtype         = G_TYPE_POINTER;
2498   prop->name          = g_strdup(key);
2499   prop->array         = nodeArray;
2500   prop->data_pointer  = (gpointer**)0;
2501   prop->data_int      = (int**)0;
2502   if (priv->elements->len > 0)
2503     prop->data_pointer  = g_malloc(sizeof(gpointer*) * priv->elements->len);
2504   for (i = 0; i < priv->elements->len; i++)
2505     {
2506       ele = _getEleArr(priv, i);
2507       DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
2508       prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes);
2509     }
2510   prop->freeTokenFunc      = freeFunc;
2511   prop->newOrCopyTokenFunc = newAndCopyFunc;
2512   prop->user_data          = user_data;
2513   g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
2514 
2515   return prop;
2516 }
2517 
freeFloatArray(gpointer obj,gpointer data)2518 static void freeFloatArray(gpointer obj, gpointer data)
2519 {
2520 #if GLIB_MINOR_VERSION > 9
2521   g_slice_free1(sizeof(float) * GPOINTER_TO_INT(data), obj);
2522 #else
2523   if (GPOINTER_TO_INT(data) > 0)
2524     g_free(obj);
2525 #endif
2526 }
newAndCopyFloatArray(gconstpointer orig,gpointer user_data)2527 static gpointer newAndCopyFloatArray(gconstpointer orig, gpointer user_data)
2528 {
2529   float *data;
2530   int nb;
2531 
2532   if (!orig)
2533     return (gpointer)0;
2534 
2535   nb = GPOINTER_TO_INT(user_data);
2536 #if GLIB_MINOR_VERSION > 9
2537   data = g_slice_alloc(sizeof(float) * nb);
2538 #else
2539   data = g_malloc(sizeof(float) * nb);
2540 #endif
2541   if (orig)
2542     memcpy(data, orig, sizeof(float) * nb);
2543   else
2544     memset(data, 0, sizeof(float) * nb);
2545 
2546   return (gpointer)data;
2547 }
2548 
2549 /**
2550  * visu_node_array_property_newFloatArray:
2551  * @nodeArray: a #VisuNodeArray object ;
2552  * @key: a string ;
2553  * @len: the number of floats to be stored per node.
2554  *
2555  * This method creates and allocates a new area to store nodes associated data that
2556  * can be retrieve with the @key. These data are constant float arrays
2557  * of length @len.
2558  *
2559  * If the property already exists, it is returned.
2560  *
2561  * Since: 3.8
2562  *
2563  * Returns: (transfer none): the newly created #VisuNodeProperty
2564  * object or the existing one.
2565  */
visu_node_array_property_newFloatArray(VisuNodeArray * nodeArray,const char * key,guint len)2566 VisuNodeProperty* visu_node_array_property_newFloatArray(VisuNodeArray* nodeArray,
2567                                                          const char* key, guint len)
2568 {
2569   VisuNodeProperty *prop;
2570   EleArr *ele;
2571   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
2572   guint i;
2573 
2574   g_return_val_if_fail(priv && key && len > 0, (VisuNodeProperty*)0);
2575 
2576   prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
2577   if (prop)
2578     return prop;
2579 
2580   DBG_fprintf(stderr, "Visu Node: adding a new float array"
2581 	      " property, called '%s'.\n", key);
2582   prop                = g_malloc(sizeof(VisuNodeProperty));
2583   prop->gtype         = G_TYPE_POINTER;
2584   prop->name          = g_strdup(key);
2585   prop->array         = nodeArray;
2586   prop->data_pointer  = (gpointer**)0;
2587   prop->data_int      = (int**)0;
2588   if (priv->elements->len > 0)
2589     prop->data_pointer  = g_malloc(sizeof(gpointer*) * priv->elements->len);
2590   for (i = 0; i < priv->elements->len; i++)
2591     {
2592       ele = _getEleArr(priv, i);
2593       DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
2594       prop->data_pointer[i] = g_malloc0(sizeof(gpointer) * ele->nNodes);
2595     }
2596   prop->freeTokenFunc      = freeFloatArray;
2597   prop->newOrCopyTokenFunc = newAndCopyFloatArray;
2598   prop->user_data          = GINT_TO_POINTER(len);
2599   g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
2600 
2601   return prop;
2602 }
2603 
2604 /**
2605  * visu_node_array_property_newInteger:
2606  * @nodeArray: a #VisuNodeArray object ;
2607  * @key: a string.
2608  *
2609  * This method creates and allocates a new area to store nodes associated integer
2610  * values. This is the same than visu_node_array_property_newPointer() but for static
2611  * integers instead of pointers as data.
2612  *
2613  * Returns: (transfer none): the newly created #VisuNodeProperty object.
2614  */
visu_node_array_property_newInteger(VisuNodeArray * nodeArray,const char * key)2615 VisuNodeProperty* visu_node_array_property_newInteger(VisuNodeArray* nodeArray,
2616 					  const char* key)
2617 {
2618   VisuNodeProperty *prop;
2619   EleArr *ele;
2620   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(nodeArray);
2621   guint i;
2622 
2623   g_return_val_if_fail(priv && key, (VisuNodeProperty*)0);
2624 
2625   prop = (VisuNodeProperty*)g_hash_table_lookup(priv->nodeProp, key);
2626   if (prop)
2627     return prop;
2628 
2629   DBG_fprintf(stderr, "Visu Node: adding a new int property, called '%s'.\n", key);
2630   prop                = g_malloc(sizeof(VisuNodeProperty));
2631   prop->gtype         = G_TYPE_INT;
2632   prop->name          = g_strdup(key);
2633   prop->array         = nodeArray;
2634   prop->data_pointer  = (gpointer**)0;
2635   prop->data_int      = (int**)0;
2636   if (priv->elements->len > 0)
2637     prop->data_int      = g_malloc(sizeof(int*) * priv->elements->len);
2638   for (i = 0; i < priv->elements->len; i++)
2639     {
2640       ele = _getEleArr(priv, i);
2641       DBG_fprintf(stderr, " | allocate (%d,%d)\n", i, ele->nNodes);
2642       prop->data_int[i] = g_malloc0(sizeof(int) * ele->nNodes);
2643     }
2644   prop->freeTokenFunc      = (GFunc)0;
2645   prop->newOrCopyTokenFunc = (GCopyFunc)0;
2646   prop->user_data          = (gpointer)0;
2647   g_hash_table_insert(priv->nodeProp, (gpointer)key, (gpointer)prop);
2648 
2649   return prop;
2650 }
2651 /**
2652  * visu_node_property_reset:
2653  * @prop: A #VisuNodeProperty object.
2654  *
2655  * Reset to zero all values, deallocating allocated memory, if any.
2656  *
2657  * Since: 3.8
2658  **/
visu_node_property_reset(VisuNodeProperty * prop)2659 void visu_node_property_reset(VisuNodeProperty* prop)
2660 {
2661   guint i, j;
2662   EleArr *ele;
2663   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(prop->array);
2664 
2665   g_return_if_fail(prop && priv);
2666 
2667   switch (prop->gtype)
2668     {
2669     case G_TYPE_POINTER:
2670       for (i = 0; i < priv->elements->len; i++)
2671         {
2672           ele = _getEleArr(priv, i);
2673           if (prop->freeTokenFunc)
2674             for (j = 0; j < ele->nNodes; j++)
2675               if (prop->data_pointer[i][j])
2676                 prop->freeTokenFunc(prop->data_pointer[i][j], prop->user_data);
2677           memset(prop->data_pointer[i], '\0', sizeof(gpointer) * ele->nNodes);
2678         }
2679       break;
2680     case G_TYPE_INT:
2681       for (i = 0; i < priv->elements->len; i++)
2682         {
2683           ele = _getEleArr(priv, i);
2684           memset(prop->data_int[i], '\0', sizeof(int) * ele->nNodes);
2685         }
2686       break;
2687     default:
2688       g_warning("Unsupported type for property '%s'.", prop->name);
2689     }
2690 }
2691 
2692 /**
2693  * visu_node_array_traceProperty:
2694  * @array: a #VisuNodeArray object ;
2695  * @id: a property name.
2696  *
2697  * This is a debug method. It outputs on stderr the values for all
2698  * nodes of the property @id.
2699  */
visu_node_array_traceProperty(VisuNodeArray * array,const gchar * id)2700 void visu_node_array_traceProperty(VisuNodeArray *array, const gchar *id)
2701 {
2702   VisuNodeProperty* prop;
2703   EleArr *ele;
2704   guint i, j;
2705   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
2706 
2707   prop = visu_node_array_getProperty(array, id);
2708 
2709   fprintf(stderr, "Visu Node: output node property '%s'.\n", id);
2710   fprintf(stderr, " | type= %d\n", (int)prop->gtype);
2711   g_return_if_fail(priv);
2712   if (prop->data_int)
2713     {
2714       for (i = 0; i < priv->elements->len; i++)
2715 	for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
2716 	  fprintf(stderr, " | %7d %3d %7d -> %d\n", ele->nodes[j].number,
2717 		  i, j, prop->data_int[i][j]);
2718     }
2719   if (prop->data_pointer)
2720     {
2721       for (i = 0; i < priv->elements->len; i++)
2722 	for (ele = _getEleArr(priv, i), j = 0; j < ele->nStoredNodes; j++)
2723 	  fprintf(stderr, " | %7d %3d %7d -> %p\n", ele->nodes[j].number,
2724 		  i, j, prop->data_pointer[i][j]);
2725     }
2726 }
2727 
2728 /**********************/
2729 /* Element properties */
2730 /**********************/
allocateEleProp(gpointer key,gpointer value,gpointer data)2731 static void allocateEleProp(gpointer key, gpointer value, gpointer data)
2732 {
2733   struct _ElementProperty *prop = (struct _ElementProperty*)value;
2734   VisuElement *ele = VISU_ELEMENT(data);
2735   GValue val = G_VALUE_INIT;
2736 
2737   DBG_fprintf(stderr, "Visu Data: allocate element property '%s'.\n", (gchar*)key);
2738   prop->init(ele, &val);
2739   g_array_append_val(prop->array, val);
2740   DBG_fprintf(stderr, " | now has %d elements.\n", prop->array->len);
2741 }
2742 /* static void freeEleProp(gpointer key, gpointer value, gpointer data _U_) */
2743 /* { */
2744 /*   struct _ElementProperty *prop = (struct _ElementProperty*)value; */
2745 /*   gint i; */
2746 
2747 /*   DBG_fprintf(stderr, "Visu Data: free element property '%s'.\n", (gchar*)key); */
2748 /*   for (i = prop->array->priv->n_values - 1; i >= 0; i--) */
2749 /*     g_value_array_remove(prop->array, i); */
2750 /* } */
freeElePropStruct(gpointer data)2751 static void freeElePropStruct(gpointer data)
2752 {
2753   struct _ElementProperty *prop = (struct _ElementProperty*)data;
2754 
2755   g_array_free(prop->array, TRUE);
2756   g_free(data);
2757 }
2758 /**
2759  * visu_node_array_setElementProperty:
2760  * @data: a #VisuNodeArray object.
2761  * @name: a string to identify the property.
2762  * @init: (scope call): an init routine.
2763  *
2764  * Create a new array to stores properties related to elements. If the
2765  * property @name already exists the previous one is destroyed. The
2766  * @init routine is called for each #VisuElement of the @data.
2767  *
2768  * Since: 3.7
2769  *
2770  * Returns: (transfer none) (element-type GLib.Value): a newly allocated array.
2771  **/
visu_node_array_setElementProperty(VisuNodeArray * data,const gchar * name,VisuNodeArrayElementPropertyInit init)2772 GArray* visu_node_array_setElementProperty(VisuNodeArray *data, const gchar *name,
2773                                            VisuNodeArrayElementPropertyInit init)
2774 {
2775   struct _ElementProperty *prop;
2776   guint i;
2777   GValue val = G_VALUE_INIT;
2778   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);
2779 
2780   g_return_val_if_fail(priv, (GArray*)0);
2781   g_return_val_if_fail(name && name[0] && init, (GArray*)0);
2782 
2783   DBG_fprintf(stderr, "Visu Data: add a new element property '%s'.\n", name);
2784   prop        = g_malloc(sizeof(struct _ElementProperty));
2785   prop->init  = init;
2786   prop->array = g_array_sized_new(FALSE, FALSE, sizeof(GValue), priv->elements->len);
2787   g_hash_table_insert(priv->eleProp, (gpointer)name, (gpointer)prop);
2788   for (i = 0; i < priv->elements->len; i++)
2789     {
2790       memset(&val, '\0', sizeof(GValue));
2791       init(_getElement(priv, i), &val);
2792       g_array_insert_val(prop->array, i, val);
2793     }
2794 
2795   return prop->array;
2796 }
2797 /**
2798  * visu_node_array_getElementProperty:
2799  * @data: a #VisuNodeArray object ;
2800  * @name: an identifier string.
2801  *
2802  * This routine is used to retrieve an array of #GValue for each
2803  * element of the @data array.
2804  *
2805  * Since: 3.7
2806  *
2807  * Returns: (transfer none) (element-type GLib.Value): an array of #GValue, indexed by the id of
2808  * each #VisuElement of @data.
2809  */
visu_node_array_getElementProperty(VisuNodeArray * data,const gchar * name)2810 GArray* visu_node_array_getElementProperty(VisuNodeArray *data, const gchar *name)
2811 {
2812   struct _ElementProperty *prop;
2813   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(data);
2814 
2815   g_return_val_if_fail(priv, (GArray*)0);
2816 
2817   DBG_fprintf(stderr, "Visu Data: get element property '%s'.\n", name);
2818   prop = (struct _ElementProperty*)g_hash_table_lookup(priv->eleProp, name);
2819   return prop ? prop->array : (GArray*)0;
2820 }
2821 
2822 /****************/
2823 /* The iterator */
2824 /****************/
2825 
2826 /**
2827  * visu_node_array_iter_new:
2828  * @array: a #VisuNodeArray object ;
2829  * @iter: (out caller-allocates) (transfer full): an alocated iterator.
2830  *
2831  * Set values to a #VisuNodeArrayIter object to iterate over nodes.
2832  * Its contain is initialised with the array size (number of elements,
2833  * number of nodes per element...).
2834  */
visu_node_array_iter_new(VisuNodeArray * array,VisuNodeArrayIter * iter)2835 void visu_node_array_iter_new(VisuNodeArray *array, VisuNodeArrayIter *iter)
2836 {
2837   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
2838   g_return_if_fail(iter && priv);
2839 
2840   iter->nAllStoredNodes = 0;
2841   iter->nElements       = 0;
2842   iter->nStoredNodes    = 0;
2843   iter->node            = (VisuNode*)0;
2844   iter->element         = (VisuElement*)0;
2845   iter->type            = ITER_NODES_BY_TYPE;
2846   iter->init            = FALSE;
2847 
2848   g_return_if_fail(VISU_IS_NODE_ARRAY(array));
2849 
2850   iter->array           = array;
2851   iter->idMax           = priv->nodeTable.idCounter - 1;
2852   iter->nAllStoredNodes = priv->nodeTable.nStoredNodes;
2853   iter->nElements       = priv->elements->len;
2854   iter->iElement        = -1;
2855   iter->itLst           = (GList*)0;
2856   iter->arr             = (GArray*)0;
2857 
2858   g_return_if_fail(priv->nodeTable.idCounter >= priv->nodeTable.nStoredNodes);
2859 }
2860 
2861 /**
2862  * visu_node_array_iterStart:
2863  * @array: a #VisuNodeArray object ;
2864  * @iter: a #VisuNodeArrayIter object.
2865  *
2866  * Initialise the node and element internal pointers for a run over the nodes.
2867  */
visu_node_array_iterStart(VisuNodeArray * array,VisuNodeArrayIter * iter)2868 void visu_node_array_iterStart(VisuNodeArray *array, VisuNodeArrayIter *iter)
2869 {
2870   EleArr *ele;
2871   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
2872 
2873   g_return_if_fail(priv && iter && array == iter->array);
2874 
2875   iter->init = TRUE;
2876 
2877   iter->iElement = -1;
2878   iter->node     = (VisuNode*)0;
2879   iter->element  = (VisuElement*)0;
2880   if (priv->elements->len == 0)
2881     return;
2882 
2883   ele = _getEleArr(priv, 0);
2884   iter->iElement = 0;
2885   iter->element  = ele->ele;
2886   /* We look for an element with stored nodes. */
2887   while (ele->nStoredNodes == 0)
2888     {
2889       iter->iElement += 1;
2890       if (iter->iElement >= priv->elements->len)
2891 	{
2892 	  /* We found nothing. */
2893 	  iter->iElement = -1;
2894 	  iter->element  = (VisuElement*)0;
2895 	  return;
2896 	}
2897       ele = _getEleArr(priv, iter->iElement);
2898       iter->element      = ele->ele;
2899       iter->nStoredNodes = ele->nStoredNodes;
2900     }
2901 
2902   iter->node         = ele->nodes;
2903   iter->nStoredNodes = ele->nStoredNodes;
2904 }
2905 
2906 /**
2907  * visu_node_array_iterStartNumber:
2908  * @array: a #VisuNodeArray object ;
2909  * @iter: a #VisuNodeArrayIter object.
2910  *
2911  * Initialise the node and element internal pointers for a run
2912  * following the node oder.
2913  */
visu_node_array_iterStartNumber(VisuNodeArray * array,VisuNodeArrayIter * iter)2914 void visu_node_array_iterStartNumber(VisuNodeArray *array, VisuNodeArrayIter *iter)
2915 {
2916   guint i;
2917   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
2918 
2919   g_return_if_fail(priv && iter && array == iter->array);
2920 
2921   iter->init = TRUE;
2922 
2923   iter->iElement = -1;
2924   iter->node     = (VisuNode*)0;
2925   iter->element  = (VisuElement*)0;
2926   if (priv->elements->len == 0)
2927     return;
2928 
2929   i = 0;
2930   iter->node = (VisuNode*)0;
2931   do
2932     {
2933       iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i);
2934       i += 1;
2935     }
2936   while (!iter->node && i < priv->nodeTable.idCounter);
2937   if (!iter->node)
2938     return;
2939   iter->iElement     = iter->node->posElement;
2940   iter->element      = _getElement(priv, iter->iElement);
2941   iter->nStoredNodes = _getEleArr(priv, iter->iElement)->nStoredNodes;
2942 }
2943 
2944 /**
2945  * visu_node_array_iterStartVisible:
2946  * @array: a #VisuNodeArray object ;
2947  * @iter: a #VisuNodeArrayIter object.
2948  *
2949  * Initialise the node and element internal pointers for a run over the
2950  * visible nodes (see visu_node_array_iterNextVisible).
2951  */
visu_node_array_iterStartVisible(VisuNodeArray * array,VisuNodeArrayIter * iter)2952 void visu_node_array_iterStartVisible(VisuNodeArray *array, VisuNodeArrayIter *iter)
2953 {
2954   visu_node_array_iterStart(array, iter);
2955   if (iter->node && iter->node->rendered && visu_element_getRendered(iter->element))
2956     /* Ok, first is good. */
2957     return;
2958 
2959   /* First was not visible, we go next. */
2960   visu_node_array_iterNextVisible(array, iter);
2961 }
2962 
2963 /**
2964  * visu_node_array_iterStartList:
2965  * @array: a #VisuNodeArray object ;
2966  * @iter: (out caller-allocates) (transfer full): an alocated
2967  * iterator.
2968  * @lst: (element-type guint) (transfer none): a list of node ids to
2969  * iterate on.
2970  *
2971  * Set values to a #VisuNodeArrayIter object to iterate over nodes of
2972  * the given list.
2973  *
2974  * Since: 3.7
2975  */
visu_node_array_iterStartList(VisuNodeArray * array,VisuNodeArrayIter * iter,GList * lst)2976 void visu_node_array_iterStartList(VisuNodeArray *array, VisuNodeArrayIter *iter, GList *lst)
2977 {
2978   GList init;
2979 
2980   g_return_if_fail(iter);
2981 
2982   iter->init = TRUE;
2983   iter->type = ITER_NODES_FROM_LIST;
2984   init.next = lst;
2985   iter->itLst = &init;
2986   visu_node_array_iterNextList(array, iter);
2987 }
2988 /**
2989  * visu_node_array_iterStartArray:
2990  * @array: a #VisuNodeArray object ;
2991  * @iter: (out caller-allocates) (transfer full): an alocated
2992  * iterator.
2993  * @arr: (element-type guint) (transfer full): an array of node ids to
2994  * iterate on.
2995  *
2996  * Set values to a #VisuNodeArrayIter object to iterate over nodes of
2997  * the given array.
2998  *
2999  * Since: 3.8
3000  */
visu_node_array_iterStartArray(VisuNodeArray * array,VisuNodeArrayIter * iter,GArray * arr)3001 void visu_node_array_iterStartArray(VisuNodeArray *array, VisuNodeArrayIter *iter,
3002                                     GArray *arr)
3003 {
3004   g_return_if_fail(iter);
3005 
3006   iter->init = TRUE;
3007   iter->type = ITER_NODES_FROM_ARRAY;
3008   iter->arr = arr;
3009   iter->itArr = 0;
3010   visu_node_array_iterNextArray(array, iter);
3011 }
3012 /**
3013  * visu_node_array_iterWhere:
3014  * @array: a #VisuNodeArray object ;
3015  * @iter: (out caller-allocates) (transfer full): an alocated
3016  * iterator.
3017  * @where: (closure data) (scope call): the function to evaluate on
3018  * each node.
3019  * @data: (closure) (allow-none): user data.
3020  *
3021  * Starts @iter to iterate on nodes of @array, when the condition
3022  * defined by @where evaluates to TRUE. @iter is then to be used with
3023  * visu_node_array_iterNextArray().
3024  *
3025  * Since: 3.8
3026  **/
visu_node_array_iterWhere(VisuNodeArray * array,VisuNodeArrayIter * iter,VisuNodeArrayIterFunc where,gpointer data)3027 void visu_node_array_iterWhere(VisuNodeArray *array, VisuNodeArrayIter *iter,
3028                                VisuNodeArrayIterFunc where, gpointer data)
3029 {
3030   GArray *arr;
3031   VisuNodeArrayIter it;
3032 
3033   g_return_if_fail(where);
3034 
3035   arr = g_array_new(FALSE, FALSE, sizeof(guint));
3036 
3037   visu_node_array_iter_new(array, &it);
3038   for (visu_node_array_iterStart(array, &it);
3039        it.node;
3040        visu_node_array_iterNext(array, &it))
3041     if (where(array, &it, data))
3042       g_array_append_val(arr, it.node->number);
3043 
3044   visu_node_array_iter_new(array, iter);
3045   visu_node_array_iterStartArray(array, iter, arr);
3046 }
3047 
3048 /**
3049  * visu_node_array_iterRestartNode:
3050  * @array: a #VisuNodeArray object ;
3051  * @iter: a #VisuNodeArrayIter object.
3052  *
3053  * The element internal pointer must be associated. Then, it returns the
3054  * node pointer to the first node for this element.
3055  */
visu_node_array_iterRestartNode(VisuNodeArray * array,VisuNodeArrayIter * iter)3056 void visu_node_array_iterRestartNode(VisuNodeArray *array, VisuNodeArrayIter *iter)
3057 {
3058   gint iEle;
3059   EleArr *ele;
3060   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3061 
3062   g_return_if_fail(priv && iter && array == iter->array);
3063 
3064   iEle = visu_node_array_getElementId(array, iter->element);
3065   g_return_if_fail(iEle >= 0);
3066 
3067   iter->init = TRUE;
3068   iter->iElement = (guint)iEle;
3069   ele = _getEleArr(priv, iEle);
3070   if (ele->nStoredNodes)
3071     iter->node = ele->nodes;
3072   else
3073     iter->node = (VisuNode*)0;
3074   iter->nStoredNodes = ele->nStoredNodes;
3075 }
3076 
3077 /**
3078  * visu_node_array_iterNext:
3079  * @array: a #VisuNodeArray object ;
3080  * @iter: a #VisuNodeArrayIter object.
3081  *
3082  * Modify node and element internal pointers to the next node, or NULL if
3083  * none remains.
3084  */
visu_node_array_iterNext(VisuNodeArray * array,VisuNodeArrayIter * iter)3085 void visu_node_array_iterNext(VisuNodeArray *array, VisuNodeArrayIter *iter)
3086 {
3087   guint iNode;
3088   EleArr *ele;
3089   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3090 
3091   g_return_if_fail(priv && iter && array == iter->array);
3092   g_return_if_fail(iter->init && iter->node && iter->iElement == iter->node->posElement);
3093 
3094   ele = _getEleArr(priv, iter->iElement);
3095   iNode = iter->node->posNode + 1;
3096   if (iNode < ele->nStoredNodes)
3097     iter->node = ele->nodes + iNode;
3098   else
3099     {
3100       iter->iElement += 1;
3101       if (iter->iElement >= priv->elements->len)
3102         {
3103           iter->node     = (VisuNode*)0;
3104           iter->iElement = -1;
3105           iter->element  = (VisuElement*)0;
3106           iter->nStoredNodes = 0;
3107         }
3108       else
3109         {
3110           ele = _getEleArr(priv, iter->iElement);
3111           iter->node     = ele->nodes;
3112           iter->element  = ele->ele;
3113           iter->nStoredNodes = ele->nStoredNodes;
3114         }
3115     }
3116 }
3117 
3118 /**
3119  * visu_node_array_iterNextList:
3120  * @array: a #VisuNodeArray object ;
3121  * @iter: a #VisuNodeArrayIter object.
3122  *
3123  * Modify node and element internal pointers to the next node from the
3124  * starting list, or NULL if none remains.
3125  *
3126  * Since: 3.7
3127  */
visu_node_array_iterNextList(VisuNodeArray * array,VisuNodeArrayIter * iter)3128 void visu_node_array_iterNextList(VisuNodeArray *array, VisuNodeArrayIter *iter)
3129 {
3130   EleArr *ele;
3131   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3132 
3133   g_return_if_fail(priv && iter && array == iter->array);
3134   g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_LIST);
3135   g_return_if_fail(iter->itLst);
3136 
3137   do
3138     {
3139       iter->itLst = g_list_next(iter->itLst);
3140       iter->node = (iter->itLst)?visu_node_array_getFromId(array, GPOINTER_TO_INT(iter->itLst->data)):(VisuNode*)0;
3141     }
3142   while (iter->itLst && !iter->node);
3143   if (!iter->itLst)
3144     {
3145       iter->itLst = (GList*)0;
3146       iter->node = (VisuNode*)0;
3147     }
3148   /* We set additional elements. */
3149   if (!iter->node)
3150     {
3151       iter->iElement = -1;
3152       iter->element  = (VisuElement*)0;
3153       iter->nStoredNodes = 0;
3154     }
3155   else
3156     {
3157       ele = _getEleArr(priv, iter->node->posElement);
3158       iter->iElement = iter->node->posElement;
3159       iter->element  = ele->ele;
3160       iter->nStoredNodes = ele->nStoredNodes;
3161     }
3162 }
3163 
3164 /**
3165  * visu_node_array_iterNextArray:
3166  * @array: a #VisuNodeArray object ;
3167  * @iter: a #VisuNodeArrayIter object.
3168  *
3169  * Modify node and element internal pointers to the next node from the
3170  * starting array, or NULL if none remains.
3171  *
3172  * Since: 3.8
3173  */
visu_node_array_iterNextArray(VisuNodeArray * array,VisuNodeArrayIter * iter)3174 void visu_node_array_iterNextArray(VisuNodeArray *array, VisuNodeArrayIter *iter)
3175 {
3176   EleArr *ele;
3177   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3178 
3179   g_return_if_fail(priv && iter && array == iter->array);
3180   g_return_if_fail(iter->init && iter->type == ITER_NODES_FROM_ARRAY);
3181 
3182   if (iter->itArr < iter->arr->len)
3183     iter->node = visu_node_array_getFromId(array, g_array_index(iter->arr, guint, iter->itArr));
3184   else
3185     {
3186       iter->node = (VisuNode*)0;
3187       g_array_unref(iter->arr);
3188     }
3189   iter->itArr += 1;
3190   /* We set additional elements. */
3191   if (!iter->node)
3192     {
3193       iter->iElement = -1;
3194       iter->element  = (VisuElement*)0;
3195       iter->nStoredNodes = 0;
3196     }
3197   else
3198     {
3199       ele = _getEleArr(priv, iter->node->posElement);
3200       iter->iElement = iter->node->posElement;
3201       iter->element  = ele->ele;
3202       iter->nStoredNodes = ele->nStoredNodes;
3203     }
3204 }
3205 
3206 /**
3207  * visu_node_array_iterNextVisible:
3208  * @array: a #VisuNodeArray object ;
3209  * @iter: a #VisuNodeArrayIter object.
3210  *
3211  * Go to the next rendered node (changing element if required).
3212  */
visu_node_array_iterNextVisible(VisuNodeArray * array,VisuNodeArrayIter * iter)3213 void visu_node_array_iterNextVisible(VisuNodeArray *array, VisuNodeArrayIter *iter)
3214 {
3215   g_return_if_fail(VISU_IS_NODE_ARRAY(array) && iter && array == iter->array);
3216 
3217   /* Get the next node, and test if it is rendered. */
3218   visu_node_array_iterNext(array, iter);
3219   if (!iter->node || (visu_element_getRendered(iter->element) && iter->node->rendered))
3220     return;
3221 
3222   /* From the current node, we go next to find one that is rendred. */
3223   for (; iter->element; visu_node_array_iterNextElement(array, iter, FALSE))
3224     if (visu_element_getRendered(iter->element))
3225       for (; iter->node; visu_node_array_iterNextNode(array, iter))
3226 	if (iter->node->rendered)
3227 	  return;
3228 }
3229 
3230 /**
3231  * visu_node_array_iterNextNode:
3232  * @array: a #VisuNodeArray object ;
3233  * @iter: a #VisuNodeArrayIter object.
3234  *
3235  * Modify node internal pointer to the next node, or NULL if
3236  * none remains. Contrary to visu_node_array_iterNext() it does not go to the
3237  * next element if one exists.
3238  */
visu_node_array_iterNextNode(VisuNodeArray * array,VisuNodeArrayIter * iter)3239 void visu_node_array_iterNextNode(VisuNodeArray *array, VisuNodeArrayIter *iter)
3240 {
3241   EleArr *ele;
3242   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3243 
3244   g_return_if_fail(priv && iter && array == iter->array);
3245   g_return_if_fail(iter->init && iter->node);
3246 
3247   ele = _getEleArr(priv, iter->node->posElement);
3248   if (iter->node->posNode + 1 < ele->nStoredNodes)
3249     iter->node = iter->node + 1;
3250   else
3251     iter->node = (VisuNode*)0;
3252 }
3253 /**
3254  * visu_node_array_iterNextNodeOriginal:
3255  * @array: a #VisuNodeArray object ;
3256  * @iter: a #VisuNodeArrayIter object.
3257  *
3258  * Modify node internal pointer to the next original node, or NULL if
3259  * none remains. Contrary to visu_node_array_iterNext() it does not go to the
3260  * next element if one exists.
3261  *
3262  * Since: 3.6
3263  */
visu_node_array_iterNextNodeOriginal(VisuNodeArray * array,VisuNodeArrayIter * iter)3264 void visu_node_array_iterNextNodeOriginal(VisuNodeArray *array, VisuNodeArrayIter *iter)
3265 {
3266   EleArr *ele;
3267   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3268 
3269   g_return_if_fail(priv && iter && array == iter->array);
3270   g_return_if_fail(iter->init && iter->node);
3271 
3272   do
3273     {
3274       ele = _getEleArr(priv, iter->node->posElement);
3275       if (iter->node->posNode + 1 < ele->nStoredNodes)
3276 	iter->node = iter->node + 1;
3277       else
3278 	iter->node = (VisuNode*)0;
3279     }
3280   while (iter->node && visu_node_array_getOriginal(array, iter->node->number) >= 0);
3281 }
3282 
3283 /**
3284  * visu_node_array_iterNextNodeNumber:
3285  * @array: a #VisuNodeArray object ;
3286  * @iter: a #VisuNodeArrayIter object.
3287  *
3288  * Modify node internal pointer to the next node, increasing the id of
3289  * the current node. The element internal pointer is also updated
3290  * accordingly. If no more nodes exist after the given one, node and
3291  * element internal pointers are set to NULL.
3292  */
visu_node_array_iterNextNodeNumber(VisuNodeArray * array,VisuNodeArrayIter * iter)3293 void visu_node_array_iterNextNodeNumber(VisuNodeArray *array, VisuNodeArrayIter *iter)
3294 {
3295   guint i;
3296   EleArr *ele;
3297   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3298 
3299   g_return_if_fail(priv && iter && array == iter->array);
3300   g_return_if_fail(iter->init && iter->node);
3301 
3302   for (i = iter->node->number + 1;
3303        !(iter->node = visu_node_array_getFromId(VISU_NODE_ARRAY(array), i)) &&
3304 	 (i < priv->nodeTable.idCounter) ; i++);
3305 
3306   if (iter->node)
3307     {
3308       ele = _getEleArr(priv, iter->node->posElement);
3309       iter->iElement = iter->node->posElement;
3310       iter->element  = ele->ele;
3311       iter->nStoredNodes = ele->nStoredNodes;
3312     }
3313   else
3314     {
3315       iter->element = (VisuElement*)0;
3316       iter->nStoredNodes = 0;
3317     }
3318 }
3319 
3320 /**
3321  * visu_node_array_iterNextElement:
3322  * @array: a #VisuNodeArray object ;
3323  * @iter: a #VisuNodeArrayIter object ;
3324  * @allowEmpty: a boolean.
3325  *
3326  * Modify element internal pointer to the next element and set node
3327  * to the first one, or NULL if none remains. If @allowEmpty is TRUE,
3328  * this iterator may return an element with no nodes, otherwise, it
3329  * skips elements with no nodes.
3330  */
visu_node_array_iterNextElement(VisuNodeArray * array,VisuNodeArrayIter * iter,gboolean allowEmpty)3331 void visu_node_array_iterNextElement(VisuNodeArray *array, VisuNodeArrayIter *iter,
3332                                      gboolean allowEmpty)
3333 {
3334   EleArr *ele;
3335   VisuNodeArrayPrivate *priv = visu_node_array_get_instance_private(array);
3336 
3337   g_return_if_fail(priv && iter && array == iter->array);
3338   g_return_if_fail(iter->init && iter->iElement < priv->elements->len);
3339 
3340   do
3341     iter->iElement += 1;
3342   while(iter->iElement < priv->elements->len &&
3343 	(!allowEmpty && _getEleArr(priv, iter->iElement)->nStoredNodes == 0));
3344 
3345   if (iter->iElement == priv->elements->len)
3346     {
3347       iter->iElement = -1;
3348       iter->node     = (VisuNode*)0;
3349       iter->element  = (VisuElement*)0;
3350       iter->nStoredNodes = 0;
3351     }
3352   else
3353     {
3354       ele = _getEleArr(priv, iter->iElement);
3355       iter->node     = ele->nodes;
3356       iter->element  = ele->ele;
3357       iter->nStoredNodes = ele->nStoredNodes;
3358     }
3359 }
3360 
3361 
3362 /*************************************/
3363 /* Additionnal routines for bindings */
3364 /*************************************/
3365 
3366 /**
3367  * visu_node_array_iter_next:
3368  * @iter: a #VisuNodeArrayIter object.
3369  *
3370  * Run the iterator to go to next item.
3371  *
3372  * Since: 3.6
3373  *
3374  * Returns: TRUE if any item is found, FALSE otherwise.
3375  */
visu_node_array_iter_next(VisuNodeArrayIter * iter)3376 gboolean visu_node_array_iter_next(VisuNodeArrayIter *iter)
3377 {
3378   if (!iter->init)
3379     switch (iter->type)
3380       {
3381       case ITER_NODES_BY_TYPE:
3382       case ITER_ELEMENTS:
3383 	visu_node_array_iterStart(iter->array, iter);
3384 	break;
3385       case ITER_NODES_BY_NUMBER:
3386       case ITER_NODES_ORIGINAL:
3387 	visu_node_array_iterStartNumber(iter->array, iter);
3388 	break;
3389       case ITER_NODES_VISIBLE:
3390 	visu_node_array_iterStartVisible(iter->array, iter);
3391 	break;
3392       case ITER_NODES_FOR_ELEMENT:
3393         visu_node_array_iterRestartNode(iter->array, iter);
3394         break;
3395       case ITER_NODES_FROM_LIST:
3396       case ITER_NODES_FROM_ARRAY:
3397         g_warning("nodes from list or array not handled.");
3398         break;
3399       }
3400   else
3401     switch (iter->type)
3402       {
3403       case ITER_NODES_BY_TYPE:
3404 	visu_node_array_iterNext(iter->array, iter);
3405 	break;
3406       case ITER_NODES_BY_NUMBER:
3407 	visu_node_array_iterNextNodeNumber(iter->array, iter);
3408 	break;
3409       case ITER_NODES_VISIBLE:
3410 	visu_node_array_iterNextVisible(iter->array, iter);
3411 	break;
3412       case ITER_NODES_ORIGINAL:
3413 	visu_node_array_iterNextNodeOriginal(iter->array, iter);
3414 	break;
3415       case ITER_NODES_FOR_ELEMENT:
3416         visu_node_array_iterNextNode(iter->array, iter);
3417         break;
3418       case ITER_NODES_FROM_LIST:
3419 	visu_node_array_iterNextList(iter->array, iter);
3420 	break;
3421       case ITER_NODES_FROM_ARRAY:
3422 	visu_node_array_iterNextArray(iter->array, iter);
3423 	break;
3424       case ITER_ELEMENTS:
3425 	visu_node_array_iterNextElement(iter->array, iter, FALSE);
3426 	break;
3427       }
3428 
3429   if (iter->node)
3430     return TRUE;
3431   else
3432     return FALSE;
3433 }
3434 /**
3435  * visu_node_array_iter_next2:
3436  * @iter1: a #VisuNodeArrayIter object.
3437  * @iter2: a #VisuNodeArrayIter object.
3438  *
3439  * Iterator to run on a pair of different nodes.
3440  *
3441  * Returns: TRUE if any item is found, FALSE otherwise.
3442  *
3443  * Since: 3.6
3444  */
visu_node_array_iter_next2(VisuNodeArrayIter * iter1,VisuNodeArrayIter * iter2)3445 gboolean visu_node_array_iter_next2(VisuNodeArrayIter *iter1, VisuNodeArrayIter *iter2)
3446 {
3447   if (!iter1->init)
3448     {
3449       visu_node_array_iterStart(iter1->array, iter1);
3450       visu_node_array_iterStart(iter1->array, iter2);
3451     }
3452   else
3453     {
3454       if (!iter1->node)
3455         return FALSE;
3456 
3457       /* DBG_fprintf(stderr, "go next %p-%p ->", (gpointer)iter1->node, (gpointer)iter2->node); */
3458       visu_node_array_iterNext(iter1->array, iter2);
3459       if (!iter2->node ||
3460 	  iter2->node->posElement > iter1->node->posElement ||
3461 	  (iter2->node->posElement == iter1->node->posElement &&
3462 	   iter2->node->posNode    >= iter1->node->posNode))
3463 	{
3464 	  visu_node_array_iterNext(iter1->array, iter1);
3465 	  if (iter1->node)
3466 	    visu_node_array_iterStart(iter1->array, iter2);
3467 	  else
3468 	    iter2->node = (VisuNode*)0;
3469 	}
3470       /* DBG_fprintf(stderr, " %p-%p\n", (gpointer)iter1->node, (gpointer)iter2->node); */
3471     }
3472 
3473   if (!iter1->node && !iter2->node)
3474     return FALSE;
3475   else
3476     return TRUE;
3477 }
3478