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