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