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 
45 #include <glib.h>
46 #include <GL/gl.h>
47 #include <math.h>
48 #include <string.h>
49 
50 #include "marks.h"
51 #include <visu_elements.h>
52 #include <visu_dataloadable.h>
53 #include <visu_configFile.h>
54 #include <visu_extension.h>
55 #include <opengl.h>
56 #include <openGLFunctions/view.h>
57 #include <openGLFunctions/text.h>
58 #include <openGLFunctions/objectList.h>
59 #include <openGLFunctions/interactive.h>
60 #include <renderingMethods/elementAtomic.h>
61 
62 
63 /**
64  * SECTION:marks
65  * @short_description: Draw features on nodes, like measurement marks
66  * or highlights.
67  *
68  * <para>#VisuGlExtMarks is used to store a set of mark on a list of
69  * nodes. A mark can be a distance measurement, an angle measurement
70  * or an highlight. The measurement marks are automatically updated by
71  * listening to the #VisuInteractive::node-selection signal. On the
72  * contrary, highlights are set, unset or toggled using
73  * visu_gl_ext_marks_setHighlight().</para>
74  * <para>In addition, #VisuGlExtMarks can be export to or loaded from an
75  * XML file thanks to visu_gl_ext_marks_exportXMLFile() and visu_gl_ext_marks_parseXMLFile().</para>
76  *
77  * Since: 3.6
78  */
79 
80 typedef enum
81   {
82     MARK_BIG_SQUARE,
83     MARK_SMALL_SQUARE,
84     MARK_HIGHLIGHT,
85     MARK_DISTANCE,
86     MARK_ANGLE,
87     MARK_LINE
88   } VisuMarkType;
89 
90 struct MarkInfo_struct
91 {
92   /* Mark type. */
93   VisuMarkType type;
94 
95   /* Id used to address the VisuNode when the
96      pointer node1 has changed, for example when a new VisuData
97      is loaded with the same geometry and we want to apply this mark. */
98   guint idNode1;
99   /* Idem for a second node. */
100   guint idNode2;
101   /* Idem for a third node. */
102   guint idNode3;
103 
104   /* List of nodes */
105   GList *nodes;
106   guint size;
107   GLfloat *coord;
108   guint *nIds;
109 };
110 
111 /**
112  * VisuNodeInfo:
113  * @id: an id;
114  * @dist: a float.
115  *
116  * Some data.
117  *
118  * Since: 3.5
119  */
120 typedef struct _VisuNodeInfo VisuNodeInfo;
121 struct _VisuNodeInfo
122 {
123   guint id;
124   float dist;
125 };
126 
127 typedef struct _ExtNode ExtNode;
128 struct _ExtNode
129 {
130   VisuGlExt parent;
131 
132   VisuGlExtMarks *marks;
133 };
134 
135 struct _VisuGlExtMarksPrivate
136 {
137   gboolean dispose_has_run;
138   ExtNode *extNode;
139 
140   /* A reference on the #VisuData and #VisuGlView it refers to. */
141   VisuGlView *view;
142   gulong cameraAngles, cameraPosition, cameraZoom, cameraPersp;
143   VisuNodeArrayRenderer *renderer;
144   gulong nodePosition, nodeRender, nodeMaterial, nodePopulation, siz_sig, dat_sig;
145 
146   /* Interactive object to get measurement signals. */
147   VisuInteractive *inter;
148   gulong nodeSelection;
149 
150   /* A list of MarkInfo_struct elements. */
151   GList *storedMarks;
152   guint hasCameraMarks;
153   gboolean drawValues;
154   GArray *cachedHighlighted;
155 
156   /* Miscellaneous. */
157   float infoRange;
158   VisuGlExtMarksHidingModes hidingMode;
159 };
160 
161 
162 enum
163   {
164     MEASUREMENT_CHANGE_SIGNAL,
165     NB_SIGNAL
166   };
167 static guint signals[NB_SIGNAL];
168 enum
169   {
170     PROP_0,
171     VIEW_PROP,
172     INTER_PROP,
173     HIDING_PROP,
174     HIGHLIGHT_PROP,
175     N_PROP
176   };
177 static GParamSpec *properties[N_PROP];
178 
179 /* Local variables. */
180 #define MARK_BIG_SQUARE_SIZE 8
181 #define MARK_SMALL_SQUARE_SIZE 4
182 static guchar markBigSquare[MARK_BIG_SQUARE_SIZE *
183 			    MARK_BIG_SQUARE_SIZE * 4];
184 static guchar markSmallSquare[MARK_SMALL_SQUARE_SIZE *
185 			      MARK_SMALL_SQUARE_SIZE * 4];
186 static float highlightFactor = 1.25f;
187 
188 /* Local methods. */
189 static ExtNode* ext_node_new(VisuGlExtMarks *marks);
190 static struct MarkInfo_struct* markNew(VisuMarkType type);
191 static void markFree(struct MarkInfo_struct *mark);
192 static VisuMarkType markRemove(VisuGlExtMarks *marks, GList *rmList);
193 static void removeDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type);
194 static void addDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type);
195 static gboolean toggleDistance(VisuGlExtMarks *marks, guint nodeRefId,
196 			       guint nodeId, gboolean set);
197 static gboolean toggleAngle(VisuGlExtMarks *marks, guint nodeRefId,
198 			    guint nodeRef2Id, guint nodeId, gboolean set);
199 static gboolean toggleHighlight(VisuGlExtMarks *marks, guint nodeId,
200 				VisuGlExtMarksStatus status, gboolean *finalStatus);
201 static gboolean setInformation(VisuGlExtMarks *marks, VisuData *dataObj, guint node);
202 static void putMark(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type);
203 static void drawMarkDot(VisuData *data, guint nodeId, VisuMarkType type);
204 static void drawMarkHighlight(VisuData *data, guint nodeId,
205                               VisuGlView *view, VisuNodeArrayRenderer *renderer);
206 static void drawMarkDistance(VisuData *data, guint nodeRefId,
207 			     guint nodeId, VisuMarkType type);
208 static void drawMarkAngle(VisuData *data, guint nodeRefId, guint nodeRef2Id,
209 			  guint nodeId, guint id);
210 static void drawMarkLine(VisuData *data _U_, GLfloat *coord, guint size);
211 
212 static void visu_gl_ext_marks_dispose(GObject *obj);
213 static void visu_gl_ext_marks_get_property(GObject* obj, guint property_id,
214                                            GValue *value, GParamSpec *pspec);
215 static void visu_gl_ext_marks_set_property(GObject* obj, guint property_id,
216                                            const GValue *value,
217                                            GParamSpec *pspec);
218 static void visu_gl_ext_marks_rebuild(VisuGlExt *ext);
219 static void visu_gl_ext_marks_draw(VisuGlExt *ext);
220 static gboolean visu_gl_ext_marks_setGlView(VisuGlExt *ext, VisuGlView *view);
221 static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface);
222 static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array);
223 static VisuNodeInfo* _getDistanceList(VisuData *data, guint nodeId, float *minVal);
224 
225 /* Local callbacks. */
226 static void _setDirty(VisuGlExtMarks *marks);
227 static void onNotifyData(VisuGlExtMarks *marks, GParamSpec *pspec,
228                          VisuNodeArrayRenderer *renderer);
229 static void _populationDecrease(VisuGlExtMarks *marks, GArray *nodes);
230 /* static void updateListOnCameraChange(VisuGlView *view, gpointer data); */
231 static gboolean onNodeSelection(VisuInteractive *inter, VisuInteractivePick kind,
232                                 VisuData *dataObje, VisuNode *node1,
233                                 VisuNode *node2, VisuNode *node3, gpointer data);
234 
235 /* V_Sim resources and paramaters. */
236 #define FLAG_RESOURCE_FACTOR "highlight_radiusFactor"
237 #define DESC_RESOURCE_FACTOR "Give the factor for the highlight radius ; one float (> 1.)"
238 static void exportResources(GString *data, VisuData *dataObj);
239 
G_DEFINE_TYPE_WITH_CODE(VisuGlExtMarks,visu_gl_ext_marks,VISU_TYPE_GL_EXT,G_ADD_PRIVATE (VisuGlExtMarks)G_IMPLEMENT_INTERFACE (VISU_TYPE_NODE_MASKER,visu_node_masker_interface_init))240 G_DEFINE_TYPE_WITH_CODE(VisuGlExtMarks, visu_gl_ext_marks, VISU_TYPE_GL_EXT,
241                         G_ADD_PRIVATE(VisuGlExtMarks)
242                         G_IMPLEMENT_INTERFACE(VISU_TYPE_NODE_MASKER,
243                                               visu_node_masker_interface_init))
244 
245 static void visu_gl_ext_marks_class_init(VisuGlExtMarksClass *klass)
246 {
247   int i;
248   float rg[2] = {1.01f, G_MAXFLOAT};
249   VisuConfigFileEntry *conf;
250 
251   G_OBJECT_CLASS(klass)->dispose  = visu_gl_ext_marks_dispose;
252   G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_marks_get_property;
253   G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_marks_set_property;
254   VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_marks_rebuild;
255   VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_marks_draw;
256   VISU_GL_EXT_CLASS(klass)->setGlView = visu_gl_ext_marks_setGlView;
257 
258   DBG_fprintf(stderr, "Visu Marks: installing signals.\n");
259   /**
260    * VisuGlExtMarks::measurementChanged:
261    * @marks: the object emitting the signal.
262    * @data: the #VisuData the measurement is done on.
263    *
264    * The list of measurements has been changed.
265    *
266    * Since: 3.6
267    */
268   signals[MEASUREMENT_CHANGE_SIGNAL] =
269     g_signal_new("measurementChanged", G_TYPE_FROM_CLASS(klass),
270                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
271                  0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
272                  G_TYPE_NONE, 1, VISU_TYPE_DATA);
273 
274   /**
275    * VisuGlExtMarks::gl-view:
276    *
277    * Store to which #VisuGlView the marks labels are aligned with.
278    *
279    * Since: 3.8
280    */
281   properties[VIEW_PROP] = g_param_spec_object("gl-view", "GlView",
282                                               "GlView mark labels are aligned with",
283                                               VISU_TYPE_GL_VIEW, G_PARAM_READWRITE);
284   /**
285    * VisuGlExtMarks::interactive:
286    *
287    * Store which #VisuInteractive the marks should react on.
288    *
289    * Since: 3.8
290    */
291   properties[INTER_PROP] = g_param_spec_object("interactive", "Interactive",
292                                                "Interactive the marks react on",
293                                                VISU_TYPE_INTERACTIVE, G_PARAM_READWRITE);
294   /**
295    * VisuGlExtMarks::hiding-mode:
296    *
297    * Mode used to hide nodes.
298    *
299    * Since: 3.8
300    */
301   properties[HIDING_PROP] = g_param_spec_uint("hiding-mode", "Hiding mode",
302                                               "nodes hiding property",
303                                               0, HIDE_NON_HIGHLIGHT, HIDE_NONE,
304                                               G_PARAM_READWRITE);
305   /**
306    * VisuGlExtMarks::highlight:
307    *
308    * Set of node ids with highlight.
309    *
310    * Since: 3.8
311    */
312   properties[HIGHLIGHT_PROP] = g_param_spec_boxed("highlight", "Highlight",
313                                                   "node ids with highlight mark.",
314                                                   G_TYPE_ARRAY, G_PARAM_READWRITE);
315 
316   g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, properties);
317 
318   /* Create the marks. */
319   for (i = 0; i < MARK_BIG_SQUARE_SIZE * MARK_BIG_SQUARE_SIZE * 4 ; i++)
320     markBigSquare[i] = 0xff;
321   for (i = 0; i < MARK_SMALL_SQUARE_SIZE * MARK_SMALL_SQUARE_SIZE * 4; i++)
322     markSmallSquare[i] = 0xff;
323 
324   conf = visu_config_file_addFloatArrayEntry(VISU_CONFIG_FILE_RESOURCE,
325                                              FLAG_RESOURCE_FACTOR,
326                                              DESC_RESOURCE_FACTOR,
327                                              1, &highlightFactor, rg, FALSE);
328   visu_config_file_entry_setVersion(conf, 3.6f);
329   visu_config_file_addExportFunction(VISU_CONFIG_FILE_RESOURCE,
330                                      exportResources);
331 }
visu_node_masker_interface_init(VisuNodeMaskerInterface * iface)332 static void visu_node_masker_interface_init(VisuNodeMaskerInterface *iface)
333 {
334   iface->apply = _maskApply;
335 }
336 
visu_gl_ext_marks_init(VisuGlExtMarks * marks)337 static void visu_gl_ext_marks_init(VisuGlExtMarks *marks)
338 {
339   DBG_fprintf(stderr, "Visu Marks: create a new object, %p.\n",
340 	      (gpointer)marks);
341 
342   marks->priv = visu_gl_ext_marks_get_instance_private(marks);
343   marks->priv->dispose_has_run = FALSE;
344 
345   marks->priv->renderer           = (VisuNodeArrayRenderer*)0;
346   marks->priv->view               = (VisuGlView*)0;
347   marks->priv->storedMarks        = (GList*)0;
348   marks->priv->cachedHighlighted  = (GArray*)0;
349   marks->priv->hasCameraMarks     = 0;
350   marks->priv->drawValues         = TRUE;
351   marks->priv->infoRange          = 1.44f;
352   marks->priv->extNode            = (ExtNode*)0;
353   marks->priv->inter              = (VisuInteractive*)0;
354   marks->priv->nodeSelection      = 0;
355   marks->priv->hidingMode         = HIDE_NONE;
356 }
357 
visu_gl_ext_marks_dispose(GObject * obj)358 static void visu_gl_ext_marks_dispose(GObject *obj)
359 {
360   VisuGlExtMarks *marks;
361 
362   DBG_fprintf(stderr, "Visu Marks: dispose object %p.\n", (gpointer)obj);
363 
364   marks = VISU_GL_EXT_MARKS(obj);
365 
366   if (marks->priv->dispose_has_run)
367     return;
368   marks->priv->dispose_has_run = TRUE;
369 
370   visu_gl_ext_marks_setDataRenderer(marks, (VisuNodeArrayRenderer*)0);
371   DBG_fprintf(stderr, " | release VisuGlView.\n");
372   visu_gl_ext_marks_setGlView(VISU_GL_EXT(marks), (VisuGlView*)0);
373   DBG_fprintf(stderr, " | free internal VisuGlExt.\n");
374   g_object_unref(G_OBJECT(marks->priv->extNode));
375 
376   DBG_fprintf(stderr, " | unconnect signals.\n");
377   visu_gl_ext_marks_setInteractive(marks, (VisuInteractive*)0);
378 
379   /* Chain up to the parent class */
380   DBG_fprintf(stderr, " | chain up.\n");
381   G_OBJECT_CLASS(visu_gl_ext_marks_parent_class)->dispose(obj);
382   DBG_fprintf(stderr, " | OK.\n");
383 }
visu_gl_ext_marks_get_property(GObject * obj,guint property_id,GValue * value,GParamSpec * pspec)384 static void visu_gl_ext_marks_get_property(GObject* obj, guint property_id,
385                                            GValue *value, GParamSpec *pspec)
386 {
387   VisuGlExtMarks *self = VISU_GL_EXT_MARKS(obj);
388 
389   DBG_fprintf(stderr, "Extension Marks: get property '%s' -> ",
390 	      g_param_spec_get_name(pspec));
391   switch (property_id)
392     {
393     case VIEW_PROP:
394       g_value_set_object(value, self->priv->view);
395       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view);
396       break;
397     case INTER_PROP:
398       g_value_set_object(value, self->priv->inter);
399       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->inter);
400       break;
401     case HIDING_PROP:
402       g_value_set_uint(value, self->priv->hidingMode);
403       DBG_fprintf(stderr, "%d.\n", self->priv->hidingMode);
404       break;
405     case HIGHLIGHT_PROP:
406       g_value_set_boxed(value, visu_gl_ext_marks_getHighlighted(self));
407       DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
408       break;
409     default:
410       /* We don't have any other property... */
411       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
412       break;
413     }
414 }
visu_gl_ext_marks_set_property(GObject * obj,guint property_id,const GValue * value,GParamSpec * pspec)415 static void visu_gl_ext_marks_set_property(GObject* obj, guint property_id,
416                                            const GValue *value, GParamSpec *pspec)
417 {
418   VisuGlExtMarks *self = VISU_GL_EXT_MARKS(obj);
419 
420   DBG_fprintf(stderr, "Extension Marks: set property '%s' -> ",
421 	      g_param_spec_get_name(pspec));
422   switch (property_id)
423     {
424     case VIEW_PROP:
425       visu_gl_ext_marks_setGlView(VISU_GL_EXT(obj),
426                                   VISU_GL_VIEW(g_value_get_object(value)));
427       DBG_fprintf(stderr, "%p.\n", (gpointer)self->priv->view);
428       break;
429     case INTER_PROP:
430       DBG_fprintf(stderr, "%p.\n", g_value_get_object(value));
431       visu_gl_ext_marks_setInteractive
432         (self, VISU_INTERACTIVE(g_value_get_object(value)));
433       break;
434     case HIDING_PROP:
435       DBG_fprintf(stderr, "%d.\n", g_value_get_uint(value));
436       visu_gl_ext_marks_setHidingMode(self, g_value_get_uint(value));
437       break;
438     case HIGHLIGHT_PROP:
439       DBG_fprintf(stderr, "%p.\n", g_value_get_boxed(value));
440       visu_gl_ext_marks_setHighlight(self, g_value_get_boxed(value), MARKS_STATUS_SET);
441       break;
442     default:
443       /* We don't have any other property... */
444       G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
445       break;
446     }
447 }
448 
449 /**
450  * visu_gl_ext_marks_new:
451  * @name: (allow-none): a possible name for the #VisuGlExt.
452  *
453  * Create a new #VisuGlExtMarks object. Make it listen to
454  * #VisuInteractive::node-selection signal to update itself
455  * automatically.
456  *
457  * Returns: the newly created object.
458  */
visu_gl_ext_marks_new(const gchar * name)459 VisuGlExtMarks* visu_gl_ext_marks_new(const gchar *name)
460 {
461   char *name_ = "MarksInv";
462   char *description = _("Draw some marks on element in video inverse.");
463   VisuGlExtMarks *marks;
464 
465   marks = VISU_GL_EXT_MARKS(g_object_new(VISU_TYPE_GL_EXT_MARKS,
466                                          "name", (name)?name:name_, "label", _(name),
467                                          "description", description, "nGlObj", 1,
468                                          "priority", VISU_GL_EXT_PRIORITY_LAST - 1,
469                                          "saveState", TRUE, NULL));
470 
471   marks->priv->extNode = ext_node_new(marks);
472 
473   return marks;
474 }
475 
476 /**
477  * visu_gl_ext_marks_getInternalList:
478  * @marks: a #VisuGlExtMarks object.
479  *
480  * Return an additional list used internaly.
481  *
482  * Since: 3.7
483  *
484  * Returns: (transfer none): a #VisuGlExt object.
485  **/
visu_gl_ext_marks_getInternalList(VisuGlExtMarks * marks)486 VisuGlExt* visu_gl_ext_marks_getInternalList(VisuGlExtMarks *marks)
487 {
488   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), (VisuGlExt*)0);
489 
490   return VISU_GL_EXT(marks->priv->extNode);
491 }
492 
markNew(VisuMarkType type)493 static struct MarkInfo_struct* markNew(VisuMarkType type)
494 {
495   struct MarkInfo_struct *mark;
496 
497   mark          = g_malloc(sizeof(struct MarkInfo_struct));
498   mark->type    = type;
499   mark->idNode1 = -1;
500   mark->idNode2 = -1;
501   mark->idNode3 = -1;
502 
503   mark->nodes   = (GList*)0;
504   mark->size    = 0;
505   mark->coord   = (GLfloat*)0;
506   mark->nIds    = (guint*)0;
507 
508   return (struct MarkInfo_struct*)mark;
509 }
markFree(struct MarkInfo_struct * mark)510 static void markFree(struct MarkInfo_struct *mark)
511 {
512   if (mark->nodes)
513     g_list_free(mark->nodes);
514 
515   if (mark->coord)
516     g_free(mark->coord);
517   if (mark->nIds)
518     g_free(mark->nIds);
519 
520   g_free(mark);
521 }
markRemove(VisuGlExtMarks * marks,GList * rmList)522 static VisuMarkType markRemove(VisuGlExtMarks *marks, GList *rmList)
523 {
524   struct MarkInfo_struct *mark;
525   gboolean hasCameraMarks;
526   VisuMarkType type;
527 
528   mark = (struct MarkInfo_struct*)rmList->data;
529   DBG_fprintf(stderr, "Visu Marks: remove mark (%d %d %d).\n",
530 	      mark->idNode1, mark->idNode2, mark->idNode3);
531   hasCameraMarks = (marks->priv->hasCameraMarks > 0);
532   type = mark->type;
533   if (mark->type == MARK_LINE)
534     marks->priv->hasCameraMarks -= 1;
535   if (mark->type == MARK_HIGHLIGHT && marks->priv->cachedHighlighted)
536     {
537       g_array_unref(marks->priv->cachedHighlighted);
538       marks->priv->cachedHighlighted = (GArray*)0;
539     }
540   markFree(mark);
541   marks->priv->storedMarks = g_list_delete_link(marks->priv->storedMarks, rmList);
542 
543   if (hasCameraMarks && marks->priv->hasCameraMarks == 0)
544     {
545       g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraAngles);
546       g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraPosition);
547       g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraZoom);
548       g_signal_handler_disconnect(G_OBJECT(marks->priv->view), marks->priv->cameraPersp);
549     }
550 
551   return type;
552 }
553 
554 /**
555  * visu_gl_ext_marks_setInteractive:
556  * @marks: a #VisuGlExtMarks object.
557  * @inter: (transfer full) (allow-none): a #VisuInteractive object.
558  *
559  * Listen to #VisuInteractive::node-selection signal to update @marks.
560  *
561  * Since: 3.7
562  **/
visu_gl_ext_marks_setInteractive(VisuGlExtMarks * marks,VisuInteractive * inter)563 void visu_gl_ext_marks_setInteractive(VisuGlExtMarks *marks, VisuInteractive *inter)
564 {
565   g_return_if_fail(VISU_IS_GL_EXT_MARKS(marks));
566 
567   DBG_fprintf(stderr, "Visu Marks: set interactive object.\n");
568   if (marks->priv->inter)
569     {
570       DBG_fprintf(stderr, " | old interactive (%p) has %d ref counts.\n",
571                   (gpointer)marks->priv->inter, G_OBJECT(marks->priv->inter)->ref_count);
572       g_signal_handler_disconnect(G_OBJECT(marks->priv->inter), marks->priv->nodeSelection);
573       g_object_unref(marks->priv->inter);
574     }
575   if (inter)
576     {
577       g_object_ref(inter);
578       marks->priv->nodeSelection = g_signal_connect(G_OBJECT(inter), "node-selection",
579                                               G_CALLBACK(onNodeSelection), (gpointer)marks);
580       DBG_fprintf(stderr, " | new interactive (%p) has %d ref counts.\n",
581                   (gpointer)inter, G_OBJECT(inter)->ref_count);
582     }
583   else
584     marks->priv->nodeSelection = 0;
585 
586   marks->priv->inter = inter;
587   g_object_notify_by_pspec(G_OBJECT(marks), properties[INTER_PROP]);
588 }
visu_gl_ext_marks_setGlView(VisuGlExt * ext,VisuGlView * view)589 static gboolean visu_gl_ext_marks_setGlView(VisuGlExt *ext, VisuGlView *view)
590 {
591   VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(ext);
592 
593   DBG_fprintf(stderr, " | marks has %d ref counts.\n",
594               G_OBJECT(marks)->ref_count);
595   /* We attach a new VisuGlView object. */
596   if (marks->priv->view == view)
597     return FALSE;
598 
599   /* We unref the previous VisuView and disconnect signals. */
600   if (marks->priv->view)
601     {
602       /* if (marks->priv->hasCameraMarks > 0) */
603       /*   { */
604       /*     g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraAngles); */
605       /*     g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraPosition); */
606       /*     g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraZoom); */
607       /*     g_signal_handler_disconnect(marks->priv->view, marks->priv->cameraPersp); */
608       /*   } */
609       g_object_unref(marks->priv->view);
610     }
611   marks->priv->view = view;
612   if (marks->priv->view)
613     {
614       /* if (marks->priv->hasCameraMarks > 0) */
615       /*   { */
616       /*     marks->priv->cameraAngles = */
617       /*       g_signal_connect(marks->priv->view, "ThetaPhiOmegaChanged", */
618       /*                        G_CALLBACK(updateListOnCameraChange), */
619       /*                        (gpointer)marks); */
620       /*     marks->priv->cameraPosition = */
621       /*       g_signal_connect(marks->priv->view, "XsYsChanged", */
622       /*                        G_CALLBACK(updateListOnCameraChange), */
623       /*                        (gpointer)marks); */
624       /*     marks->priv->cameraZoom = */
625       /*       g_signal_connect(marks->priv->view, "GrossChanged", */
626       /*                        G_CALLBACK(updateListOnCameraChange), */
627       /*                        (gpointer)marks); */
628       /*     marks->priv->cameraPersp = */
629       /*       g_signal_connect(marks->priv->view, "PerspChanged", */
630       /*                        G_CALLBACK(updateListOnCameraChange), */
631       /*                        (gpointer)marks);   */
632       /*   } */
633       /* We ref the new given view. */
634       g_object_ref(marks->priv->view);
635     }
636   g_object_notify_by_pspec(G_OBJECT(marks), properties[VIEW_PROP]);
637   return TRUE;
638 }
_setData(VisuGlExtMarks * marks,VisuNodeArray * array)639 static void _setData(VisuGlExtMarks *marks, VisuNodeArray *array)
640 {
641   GList *list, *rmList;
642   struct MarkInfo_struct*mark;
643   gboolean remove;
644   gboolean invDirty, dirDirty;
645   VisuMarkType type;
646 
647   invDirty = dirDirty = FALSE;
648   /* Mark list as dirty because of position changed, if necessary. */
649   for (list = marks->priv->storedMarks; list; list = g_list_next(list))
650     if (((struct MarkInfo_struct*)list->data)->type == MARK_HIGHLIGHT)
651       dirDirty = TRUE;
652     else
653       invDirty = TRUE;
654 
655   /* We update the list of nodes with marks. */
656   if (array)
657     {
658       /* Try to match previous marks on new VisuData. */
659       list = marks->priv->storedMarks;
660       while(list)
661 	{
662 	  mark = (struct MarkInfo_struct*)list->data;
663 	  DBG_fprintf(stderr, " | old mark %p of type %d.\n",
664 		      (gpointer)mark, mark->type);
665 	  remove = FALSE;
666 	  rmList = list;
667 	  /* We remove mark if one of the node can't be matched. */
668 	  switch (mark->type)
669 	    {
670 	    case MARK_BIG_SQUARE:
671 	    case MARK_SMALL_SQUARE:
672 	    case MARK_HIGHLIGHT:
673 	      remove = remove || !visu_node_array_getFromId(array, mark->idNode1);
674 	      break;
675 	    case MARK_DISTANCE:
676 	      remove = remove ||
677 		!visu_node_array_getFromId(array, mark->idNode1) ||
678 		!visu_node_array_getFromId(array, mark->idNode2);
679 	      break;
680 	    case MARK_ANGLE:
681 	      remove = remove ||
682 		!visu_node_array_getFromId(array, mark->idNode1) ||
683 		!visu_node_array_getFromId(array, mark->idNode2) ||
684 		!visu_node_array_getFromId(array, mark->idNode3);
685 	      break;
686 	    default:
687 	      g_warning("TODO implementation required.");
688 	    }
689 	  list = g_list_next(list);
690 	  if (remove)
691 	    {
692 	      DBG_fprintf(stderr, " | delete old mark %p of type %d.\n",
693 			  (gpointer)mark, mark->type);
694 	      type = markRemove(marks, rmList);
695               if (type == MARK_HIGHLIGHT)
696                 dirDirty = TRUE;
697               else
698                 invDirty = TRUE;
699 	    }
700 	}
701     }
702   else
703     {
704       invDirty = dirDirty = (g_list_length(marks->priv->storedMarks) > 0);
705       for (list = marks->priv->storedMarks; list; list = g_list_next(list))
706 	markFree((struct MarkInfo_struct*)list->data);
707       g_list_free(marks->priv->storedMarks);
708       marks->priv->storedMarks   = (GList*)0;
709       if (marks->priv->cachedHighlighted)
710         g_array_unref(marks->priv->cachedHighlighted);
711       marks->priv->cachedHighlighted = (GArray*)0;
712     }
713   DBG_fprintf(stderr, " | New mark list is pointing to %p.\n",
714 	      (gpointer)marks->priv->storedMarks);
715   /* Signal changes. */
716   g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]);
717   g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, array);
718   if (invDirty)
719     visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
720   if (dirDirty)
721     visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
722 }
723 /**
724  * visu_gl_ext_marks_setDataRenderer:
725  * @marks: a #VisuGlExtMarks object.
726  * @renderer: a #VisuNodeArrayRenderer object.
727  *
728  * Attach the given @marks to @data. @marks will be updated if @data
729  * is changed and internal list of marks is updated with the new nodes
730  * of @data.
731  */
visu_gl_ext_marks_setDataRenderer(VisuGlExtMarks * marks,VisuNodeArrayRenderer * renderer)732 void visu_gl_ext_marks_setDataRenderer(VisuGlExtMarks *marks, VisuNodeArrayRenderer *renderer)
733 {
734   DBG_fprintf(stderr, "Visu Marks: set new VisuNodeArrayRenderer %p (%p).\n",
735 	      (gpointer)renderer, (gpointer)marks->priv->renderer);
736 
737   if (marks->priv->renderer == renderer)
738     return;
739 
740   /* We unref the previous VisuData and disconnect signals. */
741   if (marks->priv->renderer)
742     {
743       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodePosition);
744       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodeRender);
745       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodeMaterial);
746       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->nodePopulation);
747       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->siz_sig);
748       g_signal_handler_disconnect(marks->priv->renderer, marks->priv->dat_sig);
749       g_object_unref(marks->priv->renderer);
750     }
751   marks->priv->renderer = renderer;
752   if (renderer)
753     {
754       /* We ref the new given data. */
755       g_object_ref(renderer);
756 
757       /* Connect a signal on file change to remove everything. */
758       marks->priv->nodePopulation =
759         g_signal_connect_swapped(renderer, "nodes::population-decrease",
760                                  G_CALLBACK(_populationDecrease), (gpointer)marks);
761       marks->priv->nodePosition =
762         g_signal_connect_swapped(renderer, "nodes::position",
763                                  G_CALLBACK(_setDirty), (gpointer)marks);
764       marks->priv->nodeRender =
765         g_signal_connect_swapped(renderer, "nodes::visibility",
766                                  G_CALLBACK(_setDirty), (gpointer)marks);
767       marks->priv->nodeMaterial =
768         g_signal_connect_swapped(renderer, "element-notify::color",
769                                  G_CALLBACK(_setDirty), (gpointer)marks);
770       marks->priv->siz_sig =
771         g_signal_connect_swapped(renderer, "element-size-changed",
772                                  G_CALLBACK(_setDirty), (gpointer)marks);
773       marks->priv->dat_sig =
774         g_signal_connect_swapped(renderer, "notify::data",
775                                  G_CALLBACK(onNotifyData), (gpointer)marks);
776     }
777   _setData(marks, (renderer) ? visu_node_array_renderer_getNodeArray(renderer) : (VisuNodeArray*)0);
778 }
779 
onNotifyData(VisuGlExtMarks * marks,GParamSpec * pspec _U_,VisuNodeArrayRenderer * renderer)780 static void onNotifyData(VisuGlExtMarks *marks, GParamSpec *pspec _U_,
781                          VisuNodeArrayRenderer *renderer)
782 {
783   _setData(marks, visu_node_array_renderer_getNodeArray(renderer));
784 }
_populationDecrease(VisuGlExtMarks * marks,GArray * nodes)785 static void _populationDecrease(VisuGlExtMarks *marks, GArray *nodes)
786 {
787   guint i;
788   GList *list, *rmList;
789   struct MarkInfo_struct*mark;
790   gboolean remove;
791   gboolean invDirty, dirDirty;
792   VisuMarkType type;
793 
794   DBG_fprintf(stderr, "Visu Marks: caught 'PopulationDecrease'"
795 	      " signal (%p).\n", (gpointer)marks);
796 
797   invDirty = dirDirty = FALSE;
798 
799   /* Run through the mark list to get all nodeId and look into nodes
800      to find if mark must be removed or not. */
801   DBG_fprintf(stderr, " | list contains %d elements\n",
802 	      g_list_length(marks->priv->storedMarks));
803   list = marks->priv->storedMarks;
804   while(list)
805     {
806       mark = (struct MarkInfo_struct*)list->data;
807       DBG_fprintf(stderr, " | mark %p of type %d.\n",
808 		  (gpointer)mark, mark->type);
809       /* We remove mark if one of the node is in the list. */
810       remove = FALSE;
811       rmList = list;
812       for (i = 0; !remove && i < nodes->len; i++)
813 	remove = remove ||
814 	  (g_array_index(nodes, guint, i) == mark->idNode1) ||
815 	  (g_array_index(nodes, guint, i) == mark->idNode2) ||
816 	  (g_array_index(nodes, guint, i) == mark->idNode3);
817       list = g_list_next(list);
818       if (remove)
819 	{
820 	  DBG_fprintf(stderr, " | delete mark %p of type %d.\n",
821 		      (gpointer)mark, mark->type);
822           type = markRemove(marks, rmList);
823           if (type == MARK_HIGHLIGHT)
824             dirDirty = TRUE;
825           else
826             invDirty = TRUE;
827 	}
828     }
829 
830   if (invDirty)
831     visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
832   if (dirDirty)
833     visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
834 }
_setDirty(VisuGlExtMarks * marks)835 static void _setDirty(VisuGlExtMarks *marks)
836 {
837   visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
838   visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
839 }
840 /* static void updateListOnCameraChange(VisuGlView *view _U_, gpointer data _U_) */
841 /* { */
842 /*   GList *tmpLst; */
843 /*   struct MarkInfo_struct* mark; */
844   /* VisuGlExtMarks *marks; */
845 
846   /* marks = (VisuGlExtMarks*)data; */
847   /* g_return_if_fail(data); */
848 
849 /*   for (tmpLst = mesureData->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst)) */
850 /*     { */
851 /*       mark = (struct MarkInfo_struct*)(tmpLst->data); */
852 /*       if (mark->type == PICK_MESURE_MARK_LINE) */
853 /* 	visu_interactive_class_getNodes2DCoordinates(mesureData->data, mark->nIds, g_list_length(mark->nodes), mark->coord, &mark->size); */
854 /*     } */
855 /*   marksDraw(marks, 0); */
856 /* } */
onNodeSelection(VisuInteractive * inter _U_,VisuInteractivePick pick,VisuData * dataObj,VisuNode * node0,VisuNode * node1,VisuNode * node2,gpointer data)857 static gboolean onNodeSelection(VisuInteractive *inter _U_, VisuInteractivePick pick,
858                                 VisuData *dataObj, VisuNode *node0, VisuNode *node1,
859                                 VisuNode *node2, gpointer data)
860 {
861   gint nodeId;
862   VisuMarkType type;
863   gboolean set, status;
864   GList *list;
865   VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(data);
866 
867   DBG_fprintf(stderr, "Visu Marks: get a 'node-selection' signals -> %d.\n", pick);
868 
869   switch (pick)
870     {
871     case PICK_DISTANCE:
872       if (marks->priv->drawValues)
873 	{
874 	  toggleDistance(marks, node1->number, node0->number, FALSE);
875 	  putMark(dataObj, node1->number, node0->number, MARK_DISTANCE);
876           g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj);
877           visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE);
878 	}
879       return TRUE;
880     case PICK_ANGLE:
881       if (marks->priv->drawValues)
882 	{
883 	  toggleAngle(marks, node1->number, node2->number, node0->number, FALSE);
884           g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj);
885           visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE);
886 	}
887       return TRUE;
888     case PICK_UNREFERENCE_1:
889     case PICK_UNREFERENCE_2:
890     case PICK_REFERENCE_1:
891     case PICK_REFERENCE_2:
892       type = (pick == PICK_REFERENCE_1 || pick == PICK_UNREFERENCE_1)?
893 	MARK_BIG_SQUARE:MARK_SMALL_SQUARE;
894       nodeId = -1;
895       for (list = marks->priv->storedMarks; list; list = g_list_next(list))
896 	if (((struct MarkInfo_struct*)list->data)->type == type)
897 	  nodeId = ((struct MarkInfo_struct*)list->data)->idNode1;
898       /* Erase previous one. */
899       if (nodeId >= 0)
900 	{
901 	  removeDot(marks, nodeId, type);
902 	  putMark(dataObj, -1, nodeId, type);
903 	}
904       /* Add new one. */
905       if (pick == PICK_REFERENCE_1 || pick == PICK_REFERENCE_2)
906 	{
907 	  addDot(marks, node0->number, type);
908 	  putMark(dataObj, -1, node0->number, type);
909 	}
910       visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE);
911       return TRUE;
912     case PICK_HIGHLIGHT:
913       set = toggleHighlight(marks, node0->number, MARKS_STATUS_TOGGLE, &status);
914       if (set)
915 	{
916           g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]);
917           if (marks->priv->hidingMode != HIDE_NONE)
918             visu_node_masker_emitDirty(VISU_NODE_MASKER(marks));
919           visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
920 	}
921       return TRUE;
922     case PICK_INFORMATION:
923       set = setInformation(marks, dataObj, node0->number);
924       if (set)
925 	{
926           g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj);
927           visu_gl_ext_setDirty(VISU_GL_EXT(data), TRUE);
928 	}
929       return TRUE;
930     case PICK_SELECTED:
931     default:
932       return TRUE;
933     }
934 }
935 
936 /* Method that add/remove  mark to the list of drawn marks. */
removeDot(VisuGlExtMarks * marks,guint nodeId,VisuMarkType type)937 static void removeDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type)
938 {
939   struct MarkInfo_struct *mark;
940   GList *tmpLst;
941 
942   g_return_if_fail(marks);
943 
944   /* Look for the mark. */
945   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
946     {
947       mark = (struct MarkInfo_struct*)tmpLst->data;
948       if (mark->type == type && mark->idNode1 == nodeId)
949 	{
950 	  DBG_fprintf(stderr, "Visu Marks: found a dot mark.\n");
951 	  markRemove(marks, tmpLst);
952 	  return;
953 	}
954     }
955 }
addDot(VisuGlExtMarks * marks,guint nodeId,VisuMarkType type)956 static void addDot(VisuGlExtMarks *marks, guint nodeId, VisuMarkType type)
957 {
958   struct MarkInfo_struct *mark;
959 
960   g_return_if_fail((type == MARK_BIG_SQUARE ||
961 		    type == MARK_SMALL_SQUARE ||
962 		    type == MARK_HIGHLIGHT));
963 
964   DBG_fprintf(stderr, "Visu Marks: add a new mark of type %d.\n", type);
965   mark          = markNew(type);
966   mark->idNode1 = nodeId;
967   marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark);
968   if (type == MARK_HIGHLIGHT && marks->priv->cachedHighlighted)
969     {
970       g_array_unref(marks->priv->cachedHighlighted);
971       marks->priv->cachedHighlighted = (GArray*)0;
972     }
973   return;
974 }
toggleDistance(VisuGlExtMarks * marks,guint nodeRefId,guint nodeId,gboolean set)975 static gboolean toggleDistance(VisuGlExtMarks *marks, guint nodeRefId,
976 			       guint nodeId, gboolean set)
977 {
978   struct MarkInfo_struct *mark;
979   GList *tmpLst;
980 
981   g_return_val_if_fail(marks, FALSE);
982 
983   /* Look for the mark. */
984   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
985     {
986       mark = (struct MarkInfo_struct*)tmpLst->data;
987       if (mark->type == MARK_DISTANCE &&
988 	  ((mark->idNode1 == nodeRefId && mark->idNode2 == nodeId) ||
989 	   (mark->idNode2 == nodeRefId && mark->idNode1 == nodeId)))
990 	{
991 	  DBG_fprintf(stderr, "Visu Marks: found a distance mark.\n");
992 	  if (!set)
993 	    markRemove(marks, tmpLst);
994 	  return set;
995 	}
996     }
997   /* Found none, create a new one. */
998   mark          = markNew(MARK_DISTANCE);
999   mark->idNode1 = nodeRefId;
1000   mark->idNode2 = nodeId;
1001   DBG_fprintf(stderr, "Visu Marks: add a distance mark.\n");
1002   marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark);
1003   return TRUE;
1004 }
toggleAngle(VisuGlExtMarks * marks,guint nodeRefId,guint nodeRef2Id,guint nodeId,gboolean set)1005 static gboolean toggleAngle(VisuGlExtMarks *marks, guint nodeRefId,
1006 			    guint nodeRef2Id, guint nodeId, gboolean set)
1007 {
1008   struct MarkInfo_struct *mark;
1009   GList *tmpLst;
1010 
1011   g_return_val_if_fail(marks, FALSE);
1012 
1013   /* Look for the mark. */
1014   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
1015     {
1016       mark = (struct MarkInfo_struct*)tmpLst->data;
1017       if (mark->type == MARK_ANGLE &&
1018 	  mark->idNode1 == nodeRefId &&
1019 	  ((mark->idNode2 == nodeRef2Id && mark->idNode3 == nodeId) ||
1020 	   (mark->idNode3 == nodeRef2Id && mark->idNode2 == nodeId)))
1021 	{
1022 	  DBG_fprintf(stderr, "Visu Marks: found an angle mark.\n");
1023 	  if (!set)
1024 	    markRemove(marks, tmpLst);
1025 	  return set;
1026 	}
1027     }
1028   /* Found none, create a new one. */
1029   mark          = markNew(MARK_ANGLE);
1030   mark->idNode1 = nodeRefId;
1031   mark->idNode2 = nodeRef2Id;
1032   mark->idNode3 = nodeId;
1033   DBG_fprintf(stderr, "Visu Marks: add an angle mark.\n");
1034   marks->priv->storedMarks = g_list_prepend(marks->priv->storedMarks, (gpointer)mark);
1035   return TRUE;
1036 }
toggleHighlight(VisuGlExtMarks * marks,guint nodeId,VisuGlExtMarksStatus status,gboolean * finalStatus)1037 static gboolean toggleHighlight(VisuGlExtMarks *marks, guint nodeId,
1038 				VisuGlExtMarksStatus status, gboolean *finalStatus)
1039 {
1040   struct MarkInfo_struct *mark;
1041   GList *tmpLst;
1042 
1043   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE);
1044 
1045   /* Look for the mark. */
1046   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
1047     {
1048       mark = (struct MarkInfo_struct*)tmpLst->data;
1049       if (mark->type == MARK_HIGHLIGHT &&
1050 	  mark->idNode1 == nodeId)
1051 	{
1052 	  DBG_fprintf(stderr, "Visu Marks: found a highlight mark (%d).\n", nodeId);
1053 	  if (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_UNSET)
1054 	    markRemove(marks, tmpLst);
1055 	  if (finalStatus)
1056 	    *finalStatus = (status != MARKS_STATUS_TOGGLE && status != MARKS_STATUS_UNSET);
1057 	  /* Return if it has been changed. */
1058 	  return (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_UNSET);
1059 	}
1060     }
1061   if (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET)
1062     /* Found none, create a new one. */
1063     addDot(marks, nodeId, MARK_HIGHLIGHT);
1064   if (finalStatus)
1065     *finalStatus = (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET);
1066   /* Return if it has been changed. */
1067   return (status == MARKS_STATUS_TOGGLE || status == MARKS_STATUS_SET);
1068 }
1069 /**
1070  * visu_gl_ext_marks_unHighlight:
1071  * @marks: a #VisuGlExtMarks object.
1072  *
1073  * Remove all highlight marks.
1074  *
1075  * Since: 3.8
1076  *
1077  * Returns: TRUE if anything was highlighted.
1078  **/
visu_gl_ext_marks_unHighlight(VisuGlExtMarks * marks)1079 gboolean visu_gl_ext_marks_unHighlight(VisuGlExtMarks *marks)
1080 {
1081   struct MarkInfo_struct *mark;
1082   GList *tmpLst, *rmLst;
1083   gboolean changed;
1084 
1085   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE);
1086 
1087   /* Look for the mark. */
1088   changed = FALSE;
1089   tmpLst = marks->priv->storedMarks;
1090   while (tmpLst)
1091     {
1092       mark = (struct MarkInfo_struct*)tmpLst->data;
1093       rmLst = tmpLst;
1094       tmpLst = g_list_next(tmpLst);
1095       if (mark->type == MARK_HIGHLIGHT)
1096 	{
1097           markRemove(marks, rmLst);
1098           changed = TRUE;
1099 	}
1100     }
1101   if (changed)
1102     {
1103       g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]);
1104       if (marks->priv->hidingMode != HIDE_NONE)
1105         visu_node_masker_emitDirty(VISU_NODE_MASKER(marks));
1106       visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
1107     }
1108   return changed;
1109 }
setInformation(VisuGlExtMarks * marks,VisuData * dataObj,guint node)1110 static gboolean setInformation(VisuGlExtMarks *marks, VisuData *dataObj, guint node)
1111 {
1112   VisuNodeInfo *infos;
1113   float min;
1114   GList *lst, *tmpLst, *tmpLst2;
1115   int i, n;
1116   gboolean redraw;
1117   float *dists;
1118   guint *ids;
1119   float xyz1[3], xyz2[3];
1120 
1121   g_return_val_if_fail(marks, FALSE);
1122 
1123   DBG_fprintf(stderr, "Visu Marks: compute and print distances"
1124 	      " and angles for %d.\n", node);
1125   infos = _getDistanceList(dataObj, node, &min);
1126 
1127   lst = (GList*)0;
1128   redraw = FALSE;
1129   for (i = 0; infos[i].id != node; i+= 1)
1130     if (infos[i].dist < marks->priv->infoRange * min)
1131       {
1132 	toggleDistance(marks, node, infos[i].id, TRUE);
1133 	lst = g_list_prepend(lst, GINT_TO_POINTER(infos[i].id));
1134 	redraw = TRUE;
1135       }
1136   g_free(infos);
1137 
1138   n = g_list_length(lst);
1139   if (n > 1)
1140     {
1141       n = n * (n - 1 ) / 2;
1142       DBG_fprintf(stderr, "Visu Marks: there are %d angles at max.\n", n);
1143       ids = g_malloc(sizeof(guint) * n * 2);
1144       dists = g_malloc(sizeof(float) * n);
1145       i = 0;
1146       min = G_MAXFLOAT;
1147       for (tmpLst = lst; tmpLst; tmpLst = g_list_next(tmpLst))
1148 	for (tmpLst2 = tmpLst->next; tmpLst2; tmpLst2 = g_list_next(tmpLst2))
1149 	  {
1150 	    ids[i * 2 + 0] = (guint)GPOINTER_TO_INT(tmpLst->data);
1151 	    ids[i * 2 + 1] = (guint)GPOINTER_TO_INT(tmpLst2->data);
1152 	    visu_data_getNodePosition(dataObj,
1153                                       visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj),
1154 								ids[i * 2 + 0]),
1155                                       xyz1);
1156 	    visu_data_getNodePosition(dataObj,
1157                                       visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj),
1158 								ids[i * 2 + 1]),
1159                                       xyz2);
1160 	    dists[i] =
1161 	      (xyz1[0] - xyz2[0]) * (xyz1[0] - xyz2[0]) +
1162 	      (xyz1[1] - xyz2[1]) * (xyz1[1] - xyz2[1]) +
1163 	      (xyz1[2] - xyz2[2]) * (xyz1[2] - xyz2[2]);
1164 	    DBG_fprintf(stderr, " | %d (%d %d) -> %g\n", i, ids[i * 2 + 0],
1165 			ids[i * 2 + 1], dists[i]);
1166 	    min = MIN(min, dists[i]);
1167 	    i += 1;
1168 	  }
1169 
1170       for (i = 0; i < n; i++)
1171 	if (dists[i] < (2.75f * min))
1172 	  {
1173 	    DBG_fprintf(stderr, " | %d (%d %d) -> %g OK\n", i, ids[i * 2 + 0],
1174 			ids[i * 2 + 1], dists[i]);
1175 	    toggleAngle(marks, node, ids[i * 2 + 0],
1176 			ids[i * 2 + 1], TRUE);
1177 	  }
1178       g_free(ids);
1179       g_free(dists);
1180     }
1181   g_list_free(lst);
1182 
1183   return redraw;
1184 }
1185 /**
1186  * visu_gl_ext_marks_getActive:
1187  * @marks: a #VisuGlExtMarks object.
1188  * @nodeId: a node id.
1189  *
1190  * Retrieve if @nodeId is implied any measurement marks stored in @mark.
1191  *
1192  * Returns: TRUE if @nodeId participate to any mark (distance,
1193  * angle...).
1194  */
visu_gl_ext_marks_getActive(VisuGlExtMarks * marks,guint nodeId)1195 gboolean visu_gl_ext_marks_getActive(VisuGlExtMarks *marks, guint nodeId)
1196 {
1197   GList *list;
1198   struct MarkInfo_struct *mark;
1199 
1200   g_return_val_if_fail(marks, FALSE);
1201 
1202   for (list = marks->priv->storedMarks; list; list = g_list_next(list))
1203     {
1204       mark = (struct MarkInfo_struct*)list->data;
1205       if ((mark->type == MARK_DISTANCE &&
1206 	   mark->idNode1 == nodeId) ||
1207 	  (mark->type == MARK_ANGLE &&
1208 	   mark->idNode1 == nodeId))
1209 	return TRUE;
1210     }
1211   return FALSE;
1212 }
1213 /**
1214  * visu_gl_ext_marks_getHighlighted:
1215  * @marks: a #VisuGlExtMarks object ;
1216  *
1217  * @marks has a list of mark for some nodes. These marks are only
1218  * highlight marks.
1219  *
1220  * Returns: (element-type guint) (transfer none): list of
1221  * highlighted nodes (starting from 0), should not be freed.
1222  *
1223  * Since: 3.6
1224  */
visu_gl_ext_marks_getHighlighted(const VisuGlExtMarks * marks)1225 GArray* visu_gl_ext_marks_getHighlighted(const VisuGlExtMarks *marks)
1226 {
1227   GList *tmpLst;
1228   struct MarkInfo_struct* mark;
1229 
1230   g_return_val_if_fail(marks, (GArray*)0);
1231 
1232   if (!marks->priv->cachedHighlighted)
1233     {
1234       marks->priv->cachedHighlighted = g_array_new(FALSE, FALSE, sizeof(guint));
1235       for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
1236         {
1237           mark = (struct MarkInfo_struct*)(tmpLst->data);
1238           if (mark->type == MARK_HIGHLIGHT)
1239             g_array_append_val(marks->priv->cachedHighlighted, mark->idNode1);
1240         }
1241     }
1242   return marks->priv->cachedHighlighted;
1243 }
1244 /**
1245  * visu_gl_ext_marks_getHighlightStatus:
1246  * @marks: a #VisuGlExtMarks object.
1247  * @nodeId: a node id (ranging from 0).
1248  *
1249  * Nodes can be highlighted.
1250  *
1251  * Since: 3.7
1252  *
1253  * Returns: TRUE if @nodeId has an highlight.
1254  **/
visu_gl_ext_marks_getHighlightStatus(VisuGlExtMarks * marks,guint nodeId)1255 gboolean visu_gl_ext_marks_getHighlightStatus(VisuGlExtMarks *marks, guint nodeId)
1256 {
1257   GList *tmpLst;
1258   struct MarkInfo_struct* mark;
1259 
1260   g_return_val_if_fail(marks, FALSE);
1261 
1262   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
1263     {
1264       mark = (struct MarkInfo_struct*)(tmpLst->data);
1265       if (mark->type == MARK_HIGHLIGHT && mark->idNode1 == nodeId)
1266         return TRUE;
1267     }
1268   return FALSE;
1269 }
1270 /**
1271  * visu_gl_ext_marks_setHighlight:
1272  * @marks: a #VisuGlExtMarks object ;
1273  * @nodes: (element-type guint32): a set of node ids (0 started) ;
1274  * @status: changing command.
1275  *
1276  * @marks has a list of mark for some nodes. These marks can be
1277  * highlight (or distance, angles...). Depending on @status values,
1278  * the mark may be switch on or off.
1279  *
1280  * Returns: TRUE if redraw needed.
1281  *
1282  * Since: 3.6
1283  */
visu_gl_ext_marks_setHighlight(VisuGlExtMarks * marks,GArray * nodes,VisuGlExtMarksStatus status)1284 gboolean visu_gl_ext_marks_setHighlight(VisuGlExtMarks *marks, GArray *nodes,
1285                                         VisuGlExtMarksStatus status)
1286 {
1287   gboolean redraw, res;
1288   guint i;
1289 
1290   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE);
1291 
1292   if (!nodes || !nodes->len)
1293     return FALSE;
1294 
1295   DBG_fprintf(stderr, "Visu Marks: set highlight status of list to %d.\n",
1296 	      status);
1297   redraw = FALSE;
1298   for (i = 0; i < nodes->len; i++)
1299     {
1300       res = toggleHighlight(marks, g_array_index(nodes, guint, i),
1301 			    status, (gboolean*)0);
1302       DBG_fprintf(stderr, " | %d -> %d\n", g_array_index(nodes, guint, i), res);
1303       redraw = redraw || res;
1304     }
1305   DBG_fprintf(stderr, "Visu Marks: resulting redraw %d.\n",
1306 	      redraw);
1307   if (redraw)
1308     {
1309       g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]);
1310       if (marks->priv->hidingMode != HIDE_NONE)
1311         visu_node_masker_emitDirty(VISU_NODE_MASKER(marks));
1312       visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
1313     }
1314   return redraw;
1315 }
1316 /**
1317  * visu_gl_ext_marks_setDrawValues:
1318  * @marks: a #VisuGlExtMarks object.
1319  * @status: a boolean.
1320  *
1321  * Change if the measurements are printed or not (distance length, or
1322  * angles...).
1323  *
1324  * Returns: TRUE if @marks is modified.
1325  */
visu_gl_ext_marks_setDrawValues(VisuGlExtMarks * marks,gboolean status)1326 gboolean visu_gl_ext_marks_setDrawValues(VisuGlExtMarks *marks, gboolean status)
1327 {
1328   g_return_val_if_fail(marks, FALSE);
1329 
1330   if (marks->priv->drawValues == status)
1331     return FALSE;
1332 
1333   marks->priv->drawValues = status;
1334   return TRUE;
1335 }
1336 /**
1337  * visu_gl_ext_marks_removeMeasures:
1338  * @marks: a #VisuGlExtMarks object.
1339  * @nodeId: a node id.
1340  *
1341  * This routine scans the @mark to remove all marks of distance or
1342  * angle where @nodeId is implied in.
1343  *
1344  * Returns: TRUE is @mark is changed.
1345  */
visu_gl_ext_marks_removeMeasures(VisuGlExtMarks * marks,gint nodeId)1346 gboolean visu_gl_ext_marks_removeMeasures(VisuGlExtMarks *marks, gint nodeId)
1347 {
1348   gboolean redraw;
1349   GList *list, *tmpLst;
1350   struct MarkInfo_struct *mark;
1351 
1352   g_return_val_if_fail(marks, FALSE);
1353 
1354   DBG_fprintf(stderr, "Visu Marks: remove measures (%d).\n", nodeId);
1355   redraw = FALSE;
1356   for (list = marks->priv->storedMarks; list; list = tmpLst)
1357     {
1358       tmpLst = g_list_next(list);
1359       mark = (struct MarkInfo_struct*)list->data;
1360       if ((mark->type == MARK_DISTANCE ||
1361 	   mark->type == MARK_ANGLE) &&
1362 	  (nodeId < 0 || mark->idNode1 == (guint)nodeId))
1363 	{
1364 	  markRemove(marks, list);
1365 	  redraw = TRUE;
1366 	}
1367     }
1368   if (!redraw)
1369     return FALSE;
1370 
1371   visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
1372   return TRUE;
1373 }
1374 /**
1375  * visu_gl_ext_marks_setInfos:
1376  * @marks: a #VisuGlExtMarks object.
1377  * @nodeId: a node id.
1378  * @status: a boolean.
1379  *
1380  * Depending on @status, it removes all measurements from @nodeId or
1381  * it calculate all first neighbour relations of @nodeId.
1382  *
1383  * Return: TRUE if @marks is changed.
1384  */
visu_gl_ext_marks_setInfos(VisuGlExtMarks * marks,guint nodeId,gboolean status)1385 gboolean visu_gl_ext_marks_setInfos(VisuGlExtMarks *marks, guint nodeId, gboolean status)
1386 {
1387   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE);
1388   g_return_val_if_fail(marks->priv->renderer, FALSE);
1389 
1390   DBG_fprintf(stderr, "Visu Marks: set info for node %d.\n", nodeId);
1391 
1392   if (status)
1393     {
1394       if (setInformation(marks, VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer)), nodeId))
1395 	{
1396           visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
1397 	  return TRUE;
1398 	}
1399     }
1400   else
1401     return visu_gl_ext_marks_removeMeasures(marks, nodeId);
1402 
1403   return FALSE;
1404 }
1405 
1406 
1407 /****************************/
1408 /* OpenGL drawing routines. */
1409 /****************************/
drawMarkDot(VisuData * data,guint nodeId,VisuMarkType type)1410 static void drawMarkDot(VisuData *data, guint nodeId, VisuMarkType type)
1411 {
1412   VisuNode *node;
1413   float xyz[3];
1414   VisuElement *ele;
1415 
1416   node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId);
1417   g_return_if_fail(node);
1418 
1419   /* If the node is masked, then we don't draw the dot. */
1420   if (!node->rendered)
1421     return;
1422   /* If the element is masked, then we don't draw the dot. */
1423   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node);
1424   if (!visu_element_getRendered(ele))
1425     return;
1426 
1427   DBG_fprintf(stderr, "Visu Mark: draw a mark (%d) on node %d.\n",
1428 	      (int)type, node->number);
1429 
1430   visu_data_getNodePosition(data, node, xyz);
1431   switch (type)
1432     {
1433     case MARK_BIG_SQUARE:
1434       glRasterPos3f(xyz[0], xyz[1], xyz[2]);
1435       glDrawPixels(MARK_BIG_SQUARE_SIZE,
1436 		   MARK_BIG_SQUARE_SIZE,
1437 		   GL_RGBA, GL_UNSIGNED_BYTE, markBigSquare);
1438       break;
1439     case MARK_SMALL_SQUARE:
1440       glRasterPos3f(xyz[0], xyz[1], xyz[2]);
1441       glDrawPixels(MARK_SMALL_SQUARE_SIZE,
1442 		   MARK_SMALL_SQUARE_SIZE,
1443 		   GL_RGBA, GL_UNSIGNED_BYTE, markSmallSquare);
1444       break;
1445     default:
1446       break;
1447     }
1448 }
drawMarkHighlight(VisuData * data,guint nodeId,VisuGlView * view,VisuNodeArrayRenderer * renderer)1449 static void drawMarkHighlight(VisuData *data, guint nodeId,
1450                               VisuGlView *view, VisuNodeArrayRenderer *renderer)
1451 {
1452   VisuNode *node;
1453   float xyz[3];
1454   VisuElement *ele;
1455   int nlat;
1456   float eleSize;
1457   GLUquadricObj *obj;
1458   VisuElementRenderer *eleRenderer;
1459 
1460   node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId);
1461   g_return_if_fail(node);
1462 
1463   /* If the node is masked, then we don't draw the dot. */
1464   if (!node->rendered)
1465     return;
1466   /* If the element is masked, then we don't draw the dot. */
1467   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node);
1468   if (!visu_element_getRendered(ele))
1469     return;
1470 
1471   DBG_fprintf(stderr, "Visu Mark: draw a mark highlight on node %d.\n", node->number);
1472 
1473   visu_data_getNodePosition(data, node, xyz);
1474   g_return_if_fail(view);
1475 
1476   obj = gluNewQuadric();
1477   eleRenderer = visu_node_array_renderer_get(renderer, ele);
1478   visu_element_renderer_colorize(eleRenderer, VISU_ELEMENT_RENDERER_HIGHLIGHT_SEMI);
1479   eleSize = visu_element_renderer_getExtent(eleRenderer);
1480   nlat = visu_gl_view_getDetailLevel(view, eleSize * highlightFactor);
1481   glPushMatrix();
1482   glTranslated(xyz[0], xyz[1], xyz[2]);
1483   gluSphere(obj, (double)eleSize * highlightFactor, 2 * nlat, 2 * nlat);
1484   glPopMatrix();
1485   gluDeleteQuadric(obj);
1486 }
drawMarkDistance(VisuData * data,guint nodeRefId,guint nodeId,VisuMarkType type _U_)1487 static void drawMarkDistance(VisuData *data, guint nodeRefId,
1488 			     guint nodeId, VisuMarkType type _U_)
1489 {
1490   VisuNode *nodeRef;
1491   VisuNode *node;
1492   float xyzRef[3], xyz[3];
1493   VisuElement *ele;
1494 
1495   nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRefId);
1496   node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId);
1497   g_return_if_fail(node && nodeRef);
1498 
1499   /* If one of the node is masked, then we don't draw the distance. */
1500   if (!nodeRef->rendered || !node->rendered)
1501     return;
1502 
1503   /* If one of the element is masked, then we don't draw the distance. */
1504   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef);
1505   if (!visu_element_getRendered(ele))
1506     return;
1507   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node);
1508   if (!visu_element_getRendered(ele))
1509     return;
1510 
1511   visu_data_getNodePosition(data, nodeRef, xyzRef);
1512   visu_data_getNodePosition(data, node, xyz);
1513 
1514   visu_gl_drawDistance(xyzRef, xyz, TRUE);
1515 }
drawMarkAngle(VisuData * data,guint nodeRefId,guint nodeRef2Id,guint nodeId,guint id)1516 static void drawMarkAngle(VisuData *data, guint nodeRefId, guint nodeRef2Id,
1517 			  guint nodeId, guint id)
1518 {
1519   VisuNode *nodeRef, *nodeRef2, *node;
1520   float xyzRef[3], xyzRef2[3], xyz[3];
1521   VisuElement *ele;
1522 
1523   nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRefId);
1524   nodeRef2 = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeRef2Id);
1525   node = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId);
1526   g_return_if_fail(node && nodeRef && nodeRef2);
1527 
1528   /* If one of the node is masked, then we don't draw the angle. */
1529   if (!nodeRef->rendered || !nodeRef2->rendered || !node->rendered)
1530     return;
1531 
1532   /* If one of the element is masked, then we don't draw the angle. */
1533   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef);
1534   if (!visu_element_getRendered(ele))
1535     return;
1536   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), nodeRef2);
1537   if (!visu_element_getRendered(ele))
1538     return;
1539   ele = visu_node_array_getElement(VISU_NODE_ARRAY(data), node);
1540   if (!visu_element_getRendered(ele))
1541     return;
1542 
1543   visu_data_getNodePosition(data, nodeRef, xyzRef);
1544   visu_data_getNodePosition(data, nodeRef2, xyzRef2);
1545   visu_data_getNodePosition(data, node, xyz);
1546 
1547   DBG_fprintf(stderr, "Visu PickMesure: draw an angle mark on nodes %d/%d/%d.\n",
1548 	      nodeRef->number, nodeRef2->number, node->number);
1549   visu_gl_drawAngle(xyzRef, xyzRef2, xyz, id, TRUE);
1550 }
1551 /* Calculate the node vertices coordinates (contained in the
1552 array nodevertices), from node coordinates (xn,yn) */
defineNodeVertices(int nVert,double radius,double xn,double yn,double * nodeVertices)1553 static void defineNodeVertices(int nVert, double radius, double xn, double yn, double *nodeVertices)
1554 {
1555   int i;
1556   for (i = 0; i < nVert; i++) {
1557     nodeVertices[2 * i] = (xn + radius * (cos (((2 * G_PI * i) / nVert))));
1558     nodeVertices[2 * i + 1] = (yn + radius * (sin (((2 * G_PI * i) / nVert))));
1559   }
1560 }
1561 
1562 /* Add node vertices to vertices array, from position i+1 */
addVerticesToGlobalArray(int nVert,double * nodeVertices,double * vertices,int i)1563 static void addVerticesToGlobalArray(int nVert, double *nodeVertices, double *vertices, int i)
1564 {
1565   int j;
1566   int k = 0;
1567   for (j = (i * 2) * nVert; j < (i * 2) * nVert + (nVert * 2); j += 2) {
1568     vertices[j] = nodeVertices[k];
1569     vertices[j + 1] = nodeVertices[k + 1];
1570     k += 2;
1571   }
1572 }
drawMarkLine(VisuData * data _U_,GLfloat * coord,guint size)1573 static void drawMarkLine(VisuData *data _U_, GLfloat *coord, guint size)
1574 {
1575   #define NEWLINE 1
1576   #define NEWNODE 2
1577   int i = 0, j;
1578   int elem = 0;
1579   int nNodes, nTotalVert;
1580   /***********************************/
1581   /* values must be selected by user */
1582   int nVert = 30;
1583   double radius = 30;
1584   /***********************************/
1585   double *vertices, *nodeVertices, *verticesKept;
1586   double link[2] = {0};
1587   double distance;
1588   gboolean visible = TRUE;
1589   gboolean li = FALSE;
1590 
1591   nNodes = size / 2;
1592   nTotalVert = nNodes * nVert;
1593   glMatrixMode(GL_PROJECTION);
1594   glPushMatrix();
1595   glLoadIdentity();
1596   gluOrtho2D(0.0, 600, 0., 600);
1597 
1598   glMatrixMode(GL_MODELVIEW);
1599   glPushMatrix();
1600   glLoadIdentity();
1601   vertices     = g_malloc(sizeof(double) * (nTotalVert * 2));
1602   nodeVertices = g_malloc(sizeof(double) * (nVert * 2));
1603   verticesKept = g_malloc(sizeof(double) * (nTotalVert * 2) + sizeof(int) * nTotalVert * 2);
1604 
1605   /* For each node, compute and add its vertices coordinates (nodeVertices)
1606      to the vertices global array (vertices) */
1607   for (i = 0; i < nNodes; i++){
1608     defineNodeVertices(nVert, radius, coord[2 * i], coord[2 * i + 1], nodeVertices);
1609     addVerticesToGlobalArray(nVert, nodeVertices, vertices, i);
1610   }
1611   g_free(nodeVertices);
1612   verticesKept[elem] = NEWNODE;
1613   elem++;
1614 
1615   /* For each vertex */
1616   for (i = 0; i < nTotalVert; i++){
1617     /* We notify with a marker each new node */
1618     if (i / nVert != (i - 1) / nVert){
1619       verticesKept[elem] = NEWNODE;
1620       elem++;
1621     }
1622     /* For each node */
1623     for (j = 0; j < nNodes; j++){
1624       /* If vertex i doesn't belong to node j */
1625       if (j != i / nVert){
1626         /* Distance between vertex i and node j */
1627         distance = sqrt( (pow ((coord[2 * j + 1] - vertices[2 * i + 1]), 2)) +
1628                          (pow ((coord[2 * j]     - vertices[2 * i]),     2)) );
1629         if (distance < radius)
1630           visible = FALSE;
1631       }
1632     }
1633     if (visible){
1634       verticesKept[elem] = vertices[2 * i];
1635       verticesKept[elem + 1] = vertices[2 * i + 1];
1636       elem += 2;
1637     }
1638     else {
1639       if (verticesKept[elem - 1] != NEWLINE){
1640         verticesKept[elem] = NEWLINE;
1641         elem++;
1642       }
1643       visible = TRUE;
1644     }
1645   }
1646 
1647   glLineWidth(4.0);
1648   glColor3f(1.0, 1.0, 1.0);
1649   i = 0;
1650 
1651   while (i < elem){
1652     if (verticesKept[i] == NEWLINE)
1653       i++;
1654     else if (verticesKept[i] == NEWNODE){
1655       i++;
1656       if (verticesKept[i] != NEWNODE && verticesKept[i] != NEWLINE){
1657         link[0] = verticesKept[i];
1658         link[1] = verticesKept[i + 1];
1659         li = TRUE;
1660       }
1661       else {
1662         li = FALSE;
1663         while (verticesKept[i] == NEWNODE || verticesKept[i] == NEWLINE)
1664           i++;
1665       }
1666     }
1667     else {
1668       glBegin(GL_LINES);
1669       while (verticesKept[i + 2] != NEWNODE && verticesKept[i + 2] != NEWLINE && i + 2 < elem){
1670         glVertex2f(verticesKept[i], verticesKept[i + 1]);
1671         glVertex2f(verticesKept[i + 2], verticesKept[i + 3]);
1672         i += 2;
1673       }
1674       if (i + 2 >= elem){
1675         if (li){
1676           glVertex2f(verticesKept[i], verticesKept[i + 1]);
1677           glVertex2f(link[0], link[1]);
1678         }
1679         i = elem;
1680       }
1681       else if (verticesKept[i + 2] == NEWLINE)
1682         i += 3;
1683       else if (verticesKept[i + 2] == NEWNODE){
1684         if (li){
1685           glVertex2f(verticesKept[i], verticesKept[i + 1]);
1686           glVertex2f(link[0], link[1]);
1687         }
1688         i += 2;
1689       }
1690       glEnd();
1691     }
1692   }
1693 
1694   g_free(verticesKept);
1695   g_free(vertices);
1696 
1697   glPopMatrix();
1698   glMatrixMode(GL_PROJECTION);
1699   glPopMatrix();
1700   glMatrixMode(GL_MODELVIEW);
1701 }
putMark(VisuData * data,guint nodeRefId,guint nodeId,VisuMarkType type)1702 static void putMark(VisuData *data, guint nodeRefId, guint nodeId, VisuMarkType type)
1703 {
1704   float centre[3];
1705 
1706   visu_box_getCentre(visu_boxed_getBox(VISU_BOXED(data)), centre);
1707 
1708   DBG_fprintf(stderr, "Visu Marks: draw directly a distance on front buffer.\n");
1709 
1710   glDrawBuffer(GL_FRONT);
1711   glPushAttrib(GL_ENABLE_BIT);
1712   glDisable(GL_DEPTH_TEST);
1713   glDisable(GL_LIGHTING);
1714   glDisable(GL_FOG);
1715   glEnable(GL_BLEND);
1716   glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
1717   glPushMatrix();
1718   glTranslated(-centre[0], -centre[1], -centre[2]);
1719   switch (type)
1720     {
1721     case MARK_BIG_SQUARE:
1722     case MARK_SMALL_SQUARE:
1723       drawMarkDot(data, nodeId, type);
1724       break;
1725     case MARK_DISTANCE:
1726       drawMarkDistance(data, nodeRefId, nodeId, type);
1727       break;
1728     default:
1729       g_warning("No direct drawing available for this type.");
1730     }
1731   glPopMatrix();
1732   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1733   glPopAttrib();
1734   glDrawBuffer(GL_BACK);
1735 
1736   glFlush();
1737 }
1738 
1739 
1740 /*************************/
1741 /* Resources management. */
1742 /*************************/
exportResources(GString * data,VisuData * dataObj _U_)1743 static void exportResources(GString *data, VisuData *dataObj _U_)
1744 {
1745   visu_config_file_exportComment(data, DESC_RESOURCE_FACTOR);
1746   visu_config_file_exportEntry(data, FLAG_RESOURCE_FACTOR, NULL,
1747                                "%f", highlightFactor);
1748   visu_config_file_exportComment(data, "");
1749 }
1750 
1751 
1752 /****************************/
1753 /* List drawing management. */
1754 /****************************/
visu_gl_ext_marks_rebuild(VisuGlExt * ext)1755 static void visu_gl_ext_marks_rebuild(VisuGlExt *ext)
1756 {
1757   visu_gl_text_rebuildFontList();
1758   visu_gl_ext_marks_draw(ext);
1759 }
visu_gl_ext_marks_draw(VisuGlExt * ext)1760 static void visu_gl_ext_marks_draw(VisuGlExt *ext)
1761 {
1762   VisuGlExtMarks *marks = VISU_GL_EXT_MARKS(ext);
1763   struct MarkInfo_struct *mark;
1764   GList *tmpLst;
1765   guint id;
1766   VisuData *dataObj;
1767 
1768   visu_gl_ext_setDirty(ext, FALSE);
1769 
1770   DBG_fprintf(stderr, "Visu Marks: update the list %p"
1771 	      " of all marks.\n", (gpointer)marks->priv->storedMarks);
1772   glDeleteLists(visu_gl_ext_getGlList(ext), 1);
1773 
1774   if (!marks->priv->storedMarks || !marks->priv->renderer)
1775     return;
1776 
1777   visu_gl_text_initFontList();
1778 
1779   id = 0;
1780   /* Draw the colour inverse list. */
1781   visu_gl_ext_startDrawing(ext);
1782   glEnable(GL_DEPTH_TEST);
1783   glClear(GL_DEPTH_BUFFER_BIT);
1784   /*       glDisable(GL_DEPTH_TEST); */
1785   glDisable(GL_LIGHTING);
1786   glDisable(GL_FOG);
1787   glDisable(GL_CULL_FACE);
1788   /*   glDisable(GL_DITHER); */
1789   glEnable(GL_BLEND);
1790   glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
1791   dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer));
1792   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
1793     {
1794       mark = (struct MarkInfo_struct*)tmpLst->data;
1795       DBG_fprintf(stderr, " | draw mark of type %d.\n", mark->type);
1796       switch (mark->type)
1797         {
1798         case MARK_BIG_SQUARE:
1799         case MARK_SMALL_SQUARE:
1800           drawMarkDot(dataObj, mark->idNode1, mark->type);
1801           break;
1802         case MARK_DISTANCE:
1803           drawMarkDistance(dataObj, mark->idNode1, mark->idNode2, mark->type);
1804           break;
1805         case MARK_LINE:
1806           drawMarkLine(dataObj, mark->coord, mark->size);
1807           break;
1808         case MARK_ANGLE:
1809           drawMarkAngle(dataObj, mark->idNode1, mark->idNode2, mark->idNode3, id);
1810           id += 1;
1811           break;
1812         default:
1813           break;
1814         }
1815     }
1816   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1817   visu_gl_ext_completeDrawing(ext);
1818 }
1819 
1820 /******************************************/
1821 /* XML files for marks and other exports. */
1822 /******************************************/
1823 
1824 /**
1825  * visu_gl_ext_marks_getMeasurementLabels:
1826  * @marks: a #VisuGlExtMarks object.
1827  *
1828  * Exports as a string the ids of nodes for measurement marks.
1829  *
1830  * Since: 3.6
1831  *
1832  * Returns: a newly allocated string.
1833  */
visu_gl_ext_marks_getMeasurementLabels(VisuGlExtMarks * marks)1834 gchar* visu_gl_ext_marks_getMeasurementLabels(VisuGlExtMarks *marks)
1835 {
1836   GString *str;
1837   GList *tmpLst;
1838   struct MarkInfo_struct *mark;
1839   guint i;
1840 
1841   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), (gchar*)0);
1842 
1843   str = g_string_new("#");
1844 
1845   /* Look for the mark. */
1846   for (tmpLst = marks->priv->storedMarks, i = 0; tmpLst && i < 6;
1847        tmpLst = g_list_next(tmpLst), i += 1)
1848     {
1849       mark = (struct MarkInfo_struct*)tmpLst->data;
1850       if (mark->type == MARK_DISTANCE)
1851         g_string_append_printf(str, "      %4d-%4d", mark->idNode1 + 1, mark->idNode2 + 1);
1852       else if (mark->type == MARK_ANGLE)
1853         g_string_append_printf(str, " %4d-%4d-%4d",
1854                                mark->idNode3 + 1, mark->idNode1 + 1, mark->idNode2 + 1);
1855     }
1856   if (!tmpLst)
1857     g_string_append(str, "\n");
1858   else
1859     g_string_append(str, " (truncated list)\n");
1860 
1861   return g_string_free(str, FALSE);
1862 }
1863 /**
1864  * visu_gl_ext_marks_getMeasurementStrings:
1865  * @marks: a #VisuGlExtMarks object.
1866  *
1867  * Exports as a string all measurements stored in @marks.
1868  *
1869  * Since: 3.6
1870  *
1871  * Returns: a newly allocated string.
1872  */
visu_gl_ext_marks_getMeasurementStrings(VisuGlExtMarks * marks)1873 gchar* visu_gl_ext_marks_getMeasurementStrings(VisuGlExtMarks *marks)
1874 {
1875   VisuData *dataObj;
1876   GString *str;
1877   GList *tmpLst;
1878   struct MarkInfo_struct *mark;
1879   float posSelect[3], posRef1[3], posRef2[3], dx, dy, dz, dr;
1880   float dx1, dy1, dz1, dx2, dy2, dz2, dr1, dr2, ang;
1881   VisuNode *nodes[3];
1882   gchar *lbl;
1883   gboolean export;
1884   guint i;
1885 
1886   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks) && marks->priv->renderer, (gchar*)0);
1887 
1888   str = g_string_new(" ");
1889   export = FALSE;
1890   dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer));
1891   /* Look for the mark. */
1892   for (tmpLst = marks->priv->storedMarks, i = 0; tmpLst && i < 6;
1893        tmpLst = g_list_next(tmpLst), i += 1)
1894     {
1895       mark = (struct MarkInfo_struct*)tmpLst->data;
1896       nodes[0] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode1);
1897       nodes[1] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode2);
1898       nodes[2] = visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), mark->idNode3);
1899       if (mark->type == MARK_DISTANCE)
1900 	{
1901 	  DBG_fprintf(stderr, "Visu Marks: export this distance.\n");
1902           visu_data_getNodePosition(dataObj, nodes[0], posRef1);
1903           visu_data_getNodePosition(dataObj, nodes[1], posSelect);
1904           dx = posSelect[0] - posRef1[0];
1905           dy = posSelect[1] - posRef1[1];
1906           dz = posSelect[2] - posRef1[2];
1907           dr = sqrt(dx*dx + dy*dy + dz*dz);
1908           g_string_append_printf(str, "   %12.6g", dr);
1909           export = TRUE;
1910 	}
1911       else if (mark->type == MARK_ANGLE)
1912         {
1913 	  DBG_fprintf(stderr, "Visu Marks: export this angle.\n");
1914           visu_data_getNodePosition(dataObj, nodes[0], posRef1);
1915           visu_data_getNodePosition(dataObj, nodes[1], posRef2);
1916           visu_data_getNodePosition(dataObj, nodes[2], posSelect);
1917           dx1 = posSelect[0] - posRef1[0];
1918           dy1 = posSelect[1] - posRef1[1];
1919           dz1 = posSelect[2] - posRef1[2];
1920           dx2 = posRef2[0] - posRef1[0];
1921           dy2 = posRef2[1] - posRef1[1];
1922           dz2 = posRef2[2] - posRef1[2];
1923           dr1 = sqrt(dx1*dx1 + dy1*dy1 + dz1*dz1);
1924           dr2 = sqrt(dx2*dx2 + dy2*dy2 + dz2*dz2);
1925           ang = acos((dx2*dx1+dy2*dy1+dz2*dz1)/(dr2*dr1))/TOOL_PI180;
1926           g_string_append_printf(str, "   %12.6g", ang);
1927           export = TRUE;
1928         }
1929     }
1930   if (!export)
1931     {
1932       g_string_free(str, TRUE);
1933       return (gchar*)0;
1934     }
1935   if (VISU_IS_DATA_LOADABLE(dataObj))
1936     {
1937       g_object_get(dataObj, "label", &lbl, NULL);
1938       g_string_append_printf(str, " # %s\n", lbl);
1939       g_free(lbl);
1940     }
1941 
1942   return g_string_free(str, FALSE);
1943 }
1944 
1945 /**
1946  * visu_gl_ext_marks_getHidingMode:
1947  * @marks: a #VisuGlExtMarks object.
1948  *
1949  * Retrieves the hiding mode of @marks, see #VisuGlExtMarksHidingModes.
1950  *
1951  * Since: 3.8
1952  *
1953  * Returns: a #VisuGlExtMarksHidingModes value.
1954  **/
visu_gl_ext_marks_getHidingMode(const VisuGlExtMarks * marks)1955 VisuGlExtMarksHidingModes visu_gl_ext_marks_getHidingMode(const VisuGlExtMarks *marks)
1956 {
1957   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), HIDE_NONE);
1958 
1959   return marks->priv->hidingMode;
1960 }
1961 /**
1962  * visu_gl_ext_marks_setHidingMode:
1963  * @marks: a #VisuGlExtMarks object.
1964  * @mode: a #VisuGlExtMarksHidingModes value.
1965  *
1966  * Change the hiding mode of @marks.
1967  *
1968  * Returns: TRUE if value is actually changed.
1969  **/
visu_gl_ext_marks_setHidingMode(VisuGlExtMarks * marks,VisuGlExtMarksHidingModes mode)1970 gboolean visu_gl_ext_marks_setHidingMode(VisuGlExtMarks *marks,
1971                                          VisuGlExtMarksHidingModes mode)
1972 {
1973   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks), FALSE);
1974 
1975   DBG_fprintf(stderr, "Visu Ext Marks: setting hiding mode to %d (%d).\n",
1976               mode, marks->priv->hidingMode);
1977 
1978   if (marks->priv->hidingMode == mode)
1979     return FALSE;
1980 
1981   marks->priv->hidingMode = mode;
1982   g_object_notify_by_pspec(G_OBJECT(marks), properties[HIDING_PROP]);
1983   visu_node_masker_emitDirty(VISU_NODE_MASKER(marks));
1984 
1985   return TRUE;
1986 }
1987 
_maskApply(const VisuNodeMasker * self,VisuNodeArray * array)1988 static gboolean _maskApply(const VisuNodeMasker *self, VisuNodeArray *array)
1989 {
1990   VisuGlExtMarks *marks;
1991   gboolean redraw;
1992   GArray *ids;
1993   guint i;
1994   guint nHl, *hl, j;
1995   guint min, max;
1996   VisuNodeArrayIter iter;
1997   gboolean hide;
1998 
1999   g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(self), FALSE);
2000 
2001   marks = VISU_GL_EXT_MARKS(self);
2002 
2003   if (marks->priv->hidingMode == HIDE_NONE)
2004     return FALSE;
2005 
2006   redraw = FALSE;
2007   ids = visu_gl_ext_marks_getHighlighted(marks);
2008   if (marks->priv->hidingMode == HIDE_NON_HIGHLIGHT)
2009     {
2010       /* We switch off all nodes except the highlighted ones. To avoid
2011          to run the list of highlighted nodes to many times, we create
2012          a temporary array and store the min and max indexes. */
2013       if (!ids || !ids->len)
2014         return FALSE;
2015 
2016       visu_node_array_iter_new(array, &iter);
2017 
2018       hl = g_malloc(sizeof(gint) * ids->len);
2019       nHl = 0;
2020       min = iter.nAllStoredNodes;
2021       max = 0;
2022       for (i = 0; i < ids->len; i++)
2023         {
2024           hl[nHl] = g_array_index(ids, guint, i);
2025           min = MIN(min, hl[nHl]);
2026           max = MAX(max, hl[nHl]);
2027           nHl += 1;
2028         }
2029 
2030       for (visu_node_array_iterStart(array, &iter); iter.node;
2031            visu_node_array_iterNext(array, &iter))
2032         if (iter.node->number >= min && iter.node->number <= max)
2033           {
2034             hide = TRUE;
2035             for (j = 0; hide && j < nHl; j++)
2036               hide = (iter.node->number != hl[j]);
2037             if (hide)
2038               redraw = visu_node_setVisibility(iter.node, FALSE) || redraw;
2039           }
2040         else
2041           redraw = visu_node_setVisibility(iter.node, FALSE) || redraw;
2042 
2043       g_free(hl);
2044     }
2045   else if (marks->priv->hidingMode == HIDE_HIGHLIGHT)
2046     for (i = 0; i < ids->len; i++)
2047       {
2048         redraw = visu_node_setVisibility
2049           (visu_node_array_getFromId(array, g_array_index(ids, guint, i)),
2050            FALSE) || redraw;
2051       }
2052 
2053   return redraw;
2054 }
2055 
2056 /**
2057  * visu_data_getDistanceList:
2058  * @data: a #VisuData object ;
2059  * @nodeId: a node id.
2060  * @minVal: a location for a float.
2061  *
2062  * This routine creates an array of #VisuNodeInfo, storing for each
2063  * node its node id and its distance to @nodeId. The periodicity is
2064  * NOT taken into account. The array is not distance sorted, but if
2065  * @minVal is provided, it will contain the minimal distance between
2066  * @nodeId and the other nodes.
2067  *
2068  * Since: 3.5
2069  *
2070  * Returns: an array of #VisuNodeInfo of size the number of nodes. It
2071  * is terminated by @nodeId value itself.
2072  */
_getDistanceList(VisuData * data,guint nodeId,float * minVal)2073 static VisuNodeInfo* _getDistanceList(VisuData *data, guint nodeId, float *minVal)
2074 {
2075   VisuNodeInfo *infos;
2076   int nNodes;
2077   VisuNodeArrayIter iter;
2078   VisuNode *nodeRef;
2079   float xyz[3], xyzRef[3], min;
2080 
2081   if (minVal)
2082     *minVal = -1.f;
2083 
2084   g_return_val_if_fail(VISU_IS_DATA(data), (VisuNodeInfo*)0);
2085 
2086   DBG_fprintf(stderr, "Visu Data: get distance list for node %d.\n", nodeId);
2087   nodeRef = visu_node_array_getFromId(VISU_NODE_ARRAY(data), nodeId);
2088   g_return_val_if_fail(nodeRef, (VisuNodeInfo*)0);
2089 
2090   nNodes = visu_node_array_getNNodes(VISU_NODE_ARRAY(data));
2091   infos = g_malloc(sizeof(VisuNodeInfo) * nNodes);
2092 
2093   visu_data_getNodePosition(data, nodeRef, xyzRef);
2094 
2095   min = G_MAXFLOAT;
2096   nNodes = 0;
2097   visu_node_array_iter_new(VISU_NODE_ARRAY(data), &iter);
2098   for (visu_node_array_iterStart(VISU_NODE_ARRAY(data), &iter); iter.node;
2099        visu_node_array_iterNextVisible(VISU_NODE_ARRAY(data), &iter))
2100     {
2101       infos[nNodes].id = iter.node->number;
2102       visu_data_getNodePosition(data, iter.node, xyz);
2103       infos[nNodes].dist =
2104 	(xyz[0] - xyzRef[0]) * (xyz[0] - xyzRef[0]) +
2105 	(xyz[1] - xyzRef[1]) * (xyz[1] - xyzRef[1]) +
2106 	(xyz[2] - xyzRef[2]) * (xyz[2] - xyzRef[2]);
2107       if (infos[nNodes].dist > 0.0001f)
2108 	{
2109 	  min = MIN(min, infos[nNodes].dist);
2110 	  nNodes += 1;
2111 	}
2112     }
2113   infos[nNodes].id = nodeId;
2114 
2115   DBG_fprintf(stderr, " | min value = %g.\n", min);
2116   if (minVal)
2117     *minVal = min;
2118 
2119   return infos;
2120 }
2121 
2122 
2123 /*
2124    <pick data-mode="selected" data-info="">
2125      <node id="23" />
2126      <node id="16" />
2127      <distance ref="45" id="23" />
2128    </pick>
2129 */
2130 
2131 /* Known elements. */
2132 #define PICK_PARSER_ELEMENT_PICK  "pick"
2133 #define PICK_PARSER_ELEMENT_NODE  "node"
2134 #define PICK_PARSER_ELEMENT_DIST  "distance"
2135 #define PICK_PARSER_ELEMENT_ANGL  "angle"
2136 /* Known attributes. */
2137 #define PICK_PARSER_ATTRIBUTES_MODE "info-mode"
2138 #define PICK_PARSER_ATTRIBUTES_INFO "info-data"
2139 #define PICK_PARSER_ATTRIBUTES_ID   "id"
2140 #define PICK_PARSER_ATTRIBUTES_REF  "ref"
2141 #define PICK_PARSER_ATTRIBUTES_REF2 "ref2"
2142 #define PICK_PARSER_ATTRIBUTES_HLT  "highlight"
2143 
2144 static gboolean startPick;
2145 static VisuGlExtInfosDrawId mode;
2146 static guint info;
2147 
2148 /* This method is called for every element that is parsed.
2149    The user_data must be a GList of _pick_xml. When a 'surface'
2150    element, a new struct instance is created and prepend in the list.
2151    When 'hidden-by-planes' or other qualificative elements are
2152    found, the first surface of the list is modified accordingly. */
pickXML_element(GMarkupParseContext * context _U_,const gchar * element_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)2153 static void pickXML_element(GMarkupParseContext *context _U_,
2154 			    const gchar         *element_name,
2155 			    const gchar        **attribute_names,
2156 			    const gchar        **attribute_values,
2157 			    gpointer             user_data,
2158 			    GError             **error)
2159 {
2160   GList **pickList;
2161   int i, n;
2162   guint val, val2, val3;
2163   gboolean highlight;
2164 
2165   g_return_if_fail(user_data);
2166   pickList = (GList **)user_data;
2167 
2168   DBG_fprintf(stderr, "Pick parser: found '%s' element.\n", element_name);
2169   if (!strcmp(element_name, PICK_PARSER_ELEMENT_PICK))
2170     {
2171       /* Initialise the pickList. */
2172       if (*pickList)
2173 	{
2174 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2175 		      _("DTD error: element '%s' should appear only once."),
2176 		      PICK_PARSER_ELEMENT_PICK);
2177 	  return;
2178 	}
2179       *pickList = (GList*)0;
2180       startPick = TRUE;
2181       /* Should have 2 mandatory attributes. */
2182       for (i = 0; attribute_names[i]; i++)
2183 	{
2184 	  if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_MODE))
2185 	    {
2186 	      if (!strcmp(attribute_values[i], "never"))
2187 		mode = DRAW_NEVER;
2188 	      else if (!strcmp(attribute_values[i], "selected"))
2189 		mode = DRAW_SELECTED;
2190 	      else if (!strcmp(attribute_values[i], "always"))
2191 		mode = DRAW_ALWAYS;
2192 	      else
2193 		{
2194 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2195 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2196 			      PICK_PARSER_ATTRIBUTES_MODE, attribute_values[i]);
2197 		  return;
2198 		}
2199 	    }
2200 	  else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_INFO))
2201 	    {
2202 	      n = sscanf(attribute_values[i], "%u", &info);
2203 	      if (n != 1 || info < 1)
2204 		{
2205 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2206 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2207 			      PICK_PARSER_ATTRIBUTES_INFO, attribute_values[i]);
2208 		  return;
2209 		}
2210 	    }
2211 	}
2212     }
2213   else if (!strcmp(element_name, PICK_PARSER_ELEMENT_NODE))
2214     {
2215       if (!startPick)
2216 	{
2217 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
2218 		      _("DTD error: parent element '%s' of element '%s' is missing."),
2219 		      PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_NODE);
2220 	  return;
2221 	}
2222       highlight = FALSE;
2223       /* We parse the attributes. */
2224       for (i = 0; attribute_names[i]; i++)
2225 	{
2226 	  if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID))
2227 	    {
2228 	      n = sscanf(attribute_values[i], "%u", &val);
2229 	      if (n != 1)
2230 		{
2231 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2232 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2233 			      PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]);
2234 		  return;
2235 		}
2236 	    }
2237 	  else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_HLT))
2238 	    highlight = (!strcmp(attribute_values[i], "yes") ||
2239 			 !strcmp(attribute_values[i], "Yes"));
2240 	}
2241       if (highlight)
2242 	*pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_HIGHLIGHT));
2243       else
2244 	*pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_SELECTED));
2245       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val));
2246     }
2247   else if (!strcmp(element_name, PICK_PARSER_ELEMENT_DIST))
2248     {
2249       if (!startPick)
2250 	{
2251 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
2252 		      _("DTD error: parent element '%s' of element '%s' is missing."),
2253 		      PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_DIST);
2254 	  return;
2255 	}
2256 
2257       /* We parse the attributes. */
2258       for (i = 0; attribute_names[i]; i++)
2259 	{
2260 	  if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID))
2261 	    {
2262 	      n = sscanf(attribute_values[i], "%u", &val);
2263 	      if (n != 1)
2264 		{
2265 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2266 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2267 			      PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]);
2268 		  return;
2269 		}
2270 	    }
2271 	  else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF))
2272 	    {
2273 	      n = sscanf(attribute_values[i], "%u", &val2);
2274 	      if (n != 1)
2275 		{
2276 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2277 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2278 			      PICK_PARSER_ATTRIBUTES_REF, attribute_values[i]);
2279 		  return;
2280 		}
2281 	    }
2282 	}
2283       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_DISTANCE));
2284       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val2));
2285       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val));
2286     }
2287   else if (!strcmp(element_name, PICK_PARSER_ELEMENT_ANGL))
2288     {
2289       if (!startPick)
2290 	{
2291 	  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
2292 		      _("DTD error: parent element '%s' of element '%s' is missing."),
2293 		      PICK_PARSER_ELEMENT_PICK, PICK_PARSER_ELEMENT_ANGL);
2294 	  return;
2295 	}
2296 
2297       /* We parse the attributes. */
2298       for (i = 0; attribute_names[i]; i++)
2299 	{
2300 	  if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_ID))
2301 	    {
2302 	      n = sscanf(attribute_values[i], "%u", &val);
2303 	      if (n != 1)
2304 		{
2305 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2306 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2307 			      PICK_PARSER_ATTRIBUTES_ID, attribute_values[i]);
2308 		  return;
2309 		}
2310 	    }
2311 	  else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF))
2312 	    {
2313 	      n = sscanf(attribute_values[i], "%u", &val2);
2314 	      if (n != 1)
2315 		{
2316 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2317 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2318 			      PICK_PARSER_ATTRIBUTES_REF, attribute_values[i]);
2319 		  return;
2320 		}
2321 	    }
2322 	  else if (!strcmp(attribute_names[i], PICK_PARSER_ATTRIBUTES_REF2))
2323 	    {
2324 	      n = sscanf(attribute_values[i], "%u", &val3);
2325 	      if (n != 1)
2326 		{
2327 		  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE,
2328 			      _("DTD error: attribute '%s' has an unknown value '%s'."),
2329 			      PICK_PARSER_ATTRIBUTES_REF2, attribute_values[i]);
2330 		  return;
2331 		}
2332 	    }
2333 	}
2334       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(PICK_ANGLE));
2335       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val3));
2336       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val2));
2337       *pickList = g_list_prepend(*pickList, GINT_TO_POINTER(val));
2338     }
2339   else if (startPick)
2340     {
2341       /* We silently ignore the element if pickList is unset, but
2342 	 raise an error if pickList has been set. */
2343       g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
2344 		  _("Unexpected element '%s'."), element_name);
2345     }
2346 }
2347 
2348 /* Check when a element is closed that everything required has been set. */
pickXML_end(GMarkupParseContext * context _U_,const gchar * element_name,gpointer user_data _U_,GError ** error _U_)2349 static void pickXML_end(GMarkupParseContext *context _U_,
2350 			const gchar         *element_name,
2351 			gpointer             user_data _U_,
2352 			GError             **error _U_)
2353 {
2354   if (!strcmp(element_name, PICK_PARSER_ELEMENT_PICK))
2355     startPick = FALSE;
2356 }
2357 
2358 /* What to do when an error is raised. */
pickXML_error(GMarkupParseContext * context _U_,GError * error,gpointer user_data)2359 static void pickXML_error(GMarkupParseContext *context _U_,
2360 			  GError              *error,
2361 			  gpointer             user_data)
2362 {
2363   DBG_fprintf(stderr, "Pick parser: error raised '%s'.\n", error->message);
2364   g_return_if_fail(user_data);
2365 
2366   /* We free the current list of pick. */
2367   g_list_free(*(GList**)user_data);
2368 }
2369 
2370 /**
2371  * visu_gl_ext_marks_parseXMLFile:
2372  * @marks: a #VisuGlExtMarks object.
2373  * @filename: a location to save to.
2374  * @infos: (element-type guint32) (out): a location to a #GList.
2375  * @drawingMode: a location to a flag.
2376  * @drawingInfos: a location to a flag.
2377  * @error: a location to store an error.
2378  *
2379  * This routines read from an XML file the description of selected
2380  * nodes, @mark is updated accordingly.
2381  *
2382  * Since: 3.5
2383  *
2384  * Returns: TRUE if no error.
2385  */
visu_gl_ext_marks_parseXMLFile(VisuGlExtMarks * marks,const gchar * filename,GList ** infos,VisuGlExtInfosDrawId * drawingMode,guint * drawingInfos,GError ** error)2386 gboolean visu_gl_ext_marks_parseXMLFile(VisuGlExtMarks *marks, const gchar* filename,
2387                                         GList **infos, VisuGlExtInfosDrawId *drawingMode,
2388                                         guint *drawingInfos, GError **error)
2389 {
2390   GMarkupParseContext* xmlContext;
2391   GMarkupParser parser;
2392   gboolean status;
2393   gchar *buffer;
2394   gsize size;
2395   GList *tmpLst;
2396   guint id1, id2, id3;
2397   VisuData *dataObj;
2398 
2399   g_return_val_if_fail(filename, FALSE);
2400   g_return_val_if_fail(infos && drawingMode && drawingInfos, FALSE);
2401 
2402   buffer = (gchar*)0;
2403   if (!g_file_get_contents(filename, &buffer, &size, error))
2404     return FALSE;
2405 
2406   /* Create context. */
2407   *infos = (GList*)0;
2408   parser.start_element = pickXML_element;
2409   parser.end_element   = pickXML_end;
2410   parser.text          = NULL;
2411   parser.passthrough   = NULL;
2412   parser.error         = pickXML_error;
2413   xmlContext = g_markup_parse_context_new(&parser, 0, infos, NULL);
2414 
2415   /* Parse data. */
2416   startPick = FALSE;
2417   status = g_markup_parse_context_parse(xmlContext, buffer, size, error);
2418 
2419   /* Free buffers. */
2420   g_markup_parse_context_free(xmlContext);
2421   g_free(buffer);
2422 
2423   if (!status)
2424     return FALSE;
2425 
2426   if (!*infos)
2427     {
2428       *error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_EMPTY,
2429 			  _("No picked node found."));
2430       return FALSE;
2431     }
2432 
2433   /* Need to reverse the list since elements have been prepended. */
2434   *infos        = g_list_reverse(*infos);
2435   *drawingMode  = mode;
2436   *drawingInfos = info;
2437 
2438   /* Update the current marks. */
2439   if (marks)
2440     {
2441       g_return_val_if_fail(VISU_IS_GL_EXT_MARKS(marks) && marks->priv->renderer, FALSE);
2442 
2443       dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(marks->priv->renderer));
2444       tmpLst = *infos;
2445       while(tmpLst)
2446 	{
2447 	  if (GPOINTER_TO_INT(tmpLst->data) == PICK_SELECTED)
2448 	    tmpLst = g_list_next(tmpLst);
2449 	  else if (GPOINTER_TO_INT(tmpLst->data) == PICK_HIGHLIGHT)
2450 	    {
2451 	      tmpLst = g_list_next(tmpLst);
2452 	      id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2453 	      /* We silently ignore out of bound values. */
2454 	      if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1))
2455 		toggleHighlight(marks, id1, MARKS_STATUS_SET, (gboolean*)0);
2456 	    }
2457 	  else if (GPOINTER_TO_INT(tmpLst->data) == PICK_DISTANCE)
2458 	    {
2459 	      tmpLst = g_list_next(tmpLst);
2460 	      id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2461 	      tmpLst = g_list_next(tmpLst);
2462 	      id2 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2463 	      /* We silently ignore out of bound values. */
2464 	      if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1) &&
2465 		  visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id2))
2466 		toggleDistance(marks, id1, id2, TRUE);
2467 	    }
2468 	  else if (GPOINTER_TO_INT(tmpLst->data) == PICK_ANGLE)
2469 	    {
2470 	      tmpLst = g_list_next(tmpLst);
2471 	      id1 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2472 	      tmpLst = g_list_next(tmpLst);
2473 	      id2 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2474 	      tmpLst = g_list_next(tmpLst);
2475 	      id3 = (guint)GPOINTER_TO_INT(tmpLst->data) - 1;
2476 	      /* We silently ignore out of bound values. */
2477 	      if (visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id1) &&
2478 		  visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id2) &&
2479 		  visu_node_array_getFromId(VISU_NODE_ARRAY(dataObj), id3))
2480 		toggleAngle(marks, id2, id1, id3, TRUE);
2481 	    }
2482 	  else
2483 	    {
2484 	      g_error("Should not be here!");
2485 	    }
2486 
2487 	  tmpLst = g_list_next(tmpLst);
2488 	}
2489 
2490       g_object_notify_by_pspec(G_OBJECT(marks), properties[HIGHLIGHT_PROP]);
2491       if (marks->priv->hidingMode != HIDE_NONE)
2492         visu_node_masker_emitDirty(VISU_NODE_MASKER(marks));
2493       g_signal_emit(G_OBJECT(marks), signals[MEASUREMENT_CHANGE_SIGNAL], 0, dataObj);
2494 
2495       visu_gl_ext_setDirty(VISU_GL_EXT(marks), TRUE);
2496       visu_gl_ext_setDirty(VISU_GL_EXT(marks->priv->extNode), TRUE);
2497     }
2498 
2499   return TRUE;
2500 }
2501 
2502 /**
2503  * visu_gl_ext_marks_exportXMLFile:
2504  * @marks: a #VisuGlExtMarks object.
2505  * @filename: a location to save to.
2506  * @nodes: (element-type uint): an array of node ids.
2507  * @drawingMode: a flag.
2508  * @drawingInfos: a flag.
2509  * @error: a location to store an error.
2510  *
2511  * This routines export to an XML file a description of selected
2512  * @nodes. If @nodes is NULL, the nodes stored in the @mark will be
2513  * used instead.
2514  *
2515  * Since: 3.5
2516  *
2517  * Returns: TRUE if no error.
2518  */
visu_gl_ext_marks_exportXMLFile(VisuGlExtMarks * marks,const gchar * filename,GArray * nodes,VisuGlExtInfosDrawId drawingMode,guint drawingInfos,GError ** error)2519 gboolean visu_gl_ext_marks_exportXMLFile(VisuGlExtMarks *marks, const gchar* filename,
2520                                          GArray *nodes, VisuGlExtInfosDrawId drawingMode,
2521                                          guint drawingInfos, GError **error)
2522 {
2523   gboolean valid, set;
2524   GString *output;
2525   guint i;
2526   char *modes[] = {"never", "selected", "always"};
2527   GList *tmpLst;
2528   struct MarkInfo_struct *mark;
2529 
2530   g_return_val_if_fail(marks && filename, FALSE);
2531 
2532   /*
2533    <pick data-mode="selected" data-info="0">
2534      <node id="23" />
2535      <node id="16" highlight="yes" />
2536      <distance ref="45" id="23" />
2537      <angle ref="45" ref2="65" id="23" />
2538    </pick>
2539   */
2540 
2541   output = g_string_new("  <pick");
2542   g_string_append_printf(output, " data-mode=\"%s\" data-infos=\"%d\">\n",
2543 			 modes[drawingMode], drawingInfos);
2544   if (nodes)
2545     for (i = 0; i < nodes->len; i++)
2546       {
2547 	set = FALSE;
2548 	/* We print them only if they are not part of marks. */
2549 	for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
2550 	  {
2551 	    mark = (struct MarkInfo_struct*)(tmpLst->data);
2552 	    set = set || ( (mark->type == MARK_DISTANCE &&
2553 			    g_array_index(nodes, guint, i) == mark->idNode2) ||
2554 			   (mark->type == MARK_HIGHLIGHT &&
2555 			    g_array_index(nodes, guint, i) == mark->idNode1) );
2556 	  }
2557 	if (!set)
2558 	  g_string_append_printf(output, "    <node id=\"%d\" />\n", g_array_index(nodes, guint, i) + 1);
2559       }
2560   for (tmpLst = marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
2561     {
2562       mark = (struct MarkInfo_struct*)(tmpLst->data);
2563       if (mark->type == MARK_DISTANCE)
2564 	g_string_append_printf(output, "    <distance ref=\"%d\" id=\"%d\" />\n",
2565 			       mark->idNode1 + 1, mark->idNode2 + 1);
2566       else if (mark->type == MARK_ANGLE)
2567 	g_string_append_printf(output,
2568 			       "    <angle ref=\"%d\" ref2=\"%d\" id=\"%d\" />\n",
2569 			       mark->idNode1 + 1, mark->idNode2 + 1,
2570 			       mark->idNode3 + 1);
2571       else if (mark->type == MARK_HIGHLIGHT)
2572 	g_string_append_printf(output, "    <node id=\"%d\" highlight=\"yes\" />\n",
2573 			       mark->idNode1 + 1);
2574     }
2575   g_string_append(output, "  </pick>");
2576 
2577   valid = tool_XML_substitute(output, filename, "pick", error);
2578   if (!valid)
2579     {
2580       g_string_free(output, TRUE);
2581       return FALSE;
2582     }
2583 
2584   valid = g_file_set_contents(filename, output->str, -1, error);
2585   g_string_free(output, TRUE);
2586   return valid;
2587 }
2588 
2589 
2590 /* Local VisuGlExt for direct node marks. */
2591 typedef struct _ExtNodeClass ExtNodeClass;
2592 struct _ExtNodeClass
2593 {
2594   VisuGlExtClass parent;
2595 };
2596 
2597 static void ext_node_rebuild(VisuGlExt *ext);
2598 static void ext_node_draw(VisuGlExt *ext);
2599 
2600 #define TYPE_EXT_NODE          (ext_node_get_type())
2601 GType ext_node_get_type(void);
2602 
2603 #define EXT_NODE(obj)          (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_EXT_NODE, ExtNode))
2604 
G_DEFINE_TYPE(ExtNode,ext_node,VISU_TYPE_GL_EXT)2605 G_DEFINE_TYPE (ExtNode, ext_node, VISU_TYPE_GL_EXT)
2606 
2607 static void ext_node_class_init(ExtNodeClass *class)
2608 {
2609   DBG_fprintf(stderr, "Visu Marks: create internal ExtNode class.\n");
2610   VISU_GL_EXT_CLASS(class)->rebuild = ext_node_rebuild;
2611   VISU_GL_EXT_CLASS(class)->draw = ext_node_draw;
2612 }
2613 
ext_node_init(ExtNode * marks)2614 static void ext_node_init(ExtNode *marks)
2615 {
2616   DBG_fprintf(stderr, "Visu Marks: initialise new ExtNode object.\n");
2617   marks->marks = (VisuGlExtMarks*)0;
2618 }
2619 
ext_node_new(VisuGlExtMarks * marks)2620 static ExtNode* ext_node_new(VisuGlExtMarks *marks)
2621 {
2622   ExtNode *ext;
2623 
2624   ext = EXT_NODE(g_object_new(TYPE_EXT_NODE,
2625                               "name", "Marks", "label", _("Marks - classical"),
2626                               "description", _("Draw some marks on element."),
2627                               "nGlObj", 1, "priority", VISU_GL_EXT_PRIORITY_LOW, NULL));
2628 
2629   ext->marks = marks;
2630 
2631   return ext;
2632 }
2633 
ext_node_rebuild(VisuGlExt * ext)2634 static void ext_node_rebuild(VisuGlExt *ext)
2635 {
2636   ext_node_draw(ext);
2637 }
ext_node_draw(VisuGlExt * ext)2638 static void ext_node_draw(VisuGlExt *ext)
2639 {
2640   ExtNode *extNode = EXT_NODE(ext);
2641   struct MarkInfo_struct *mark;
2642   GList *tmpLst;
2643   VisuData *dataObj;
2644 
2645   DBG_fprintf(stderr, "Visu Marks: update the list %p"
2646 	      " of all marks.\n", (gpointer)extNode->marks->priv->storedMarks);
2647 
2648   glDeleteLists(visu_gl_ext_getGlList(ext), 1);
2649   visu_gl_ext_setDirty(ext, FALSE);
2650 
2651   if (!extNode->marks->priv->storedMarks || !extNode->marks->priv->renderer)
2652     return;
2653 
2654   /* Draw the classical list. */
2655   visu_gl_ext_startDrawing(ext);
2656   glEnable(GL_LIGHTING);
2657   dataObj = VISU_DATA(visu_node_array_renderer_getNodeArray(extNode->marks->priv->renderer));
2658   for (tmpLst = extNode->marks->priv->storedMarks; tmpLst; tmpLst = g_list_next(tmpLst))
2659     {
2660       mark = (struct MarkInfo_struct*)tmpLst->data;
2661       if (mark->type == MARK_HIGHLIGHT)
2662         {
2663           DBG_fprintf(stderr, " | draw mark of type %d.\n", mark->type);
2664           drawMarkHighlight(dataObj, mark->idNode1, extNode->marks->priv->view, extNode->marks->priv->renderer);
2665         }
2666     }
2667   visu_gl_ext_completeDrawing(ext);
2668 }
2669