1 /* EXTRAITS DE LA LICENCE 2 Copyright CEA, contributeurs : Damien 3 CALISTE, laboratoire L_Sim, (2011-2019) 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 : Damien 25 CALISTE, laboratoire L_Sim, (2011-2019) 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 "node_vectors.h" 46 47 #include <GL/gl.h> 48 #include <GL/glu.h> 49 #include <math.h> 50 51 #include <opengl.h> 52 #include <openGLFunctions/text.h> 53 #include <coreTools/toolMatrix.h> 54 #include <coreTools/toolColor.h> 55 #include <renderingMethods/elementAtomic.h> 56 #include <extraFunctions/iface_sourceable.h> 57 58 #include <visu_configFile.h> 59 60 61 62 /** 63 * SECTION:node_vectors 64 * @short_description: Draw arrows at each node to represent forces, 65 * displacements, vibrations... 66 * 67 * <para>A generic #VisuGlExt to represent vectors on nodes.</para> 68 */ 69 70 enum 71 { 72 TAIL_LENGTH, 73 TAIL_RADIUS, 74 TAIL_NLAT, 75 HEAD_LENGTH, 76 HEAD_RADIUS, 77 HEAD_NLAT, 78 N_ARROW_DEFS 79 }; 80 81 /** 82 * VisuGlExtNodeVectorsClass: 83 * @parent: the parent class; 84 * 85 * A short way to identify #_VisuGlExtNodeVectorsClass structure. 86 * 87 * Since: 3.7 88 */ 89 /** 90 * VisuGlExtNodeVectors: 91 * 92 * An opaque structure. 93 * 94 * Since: 3.7 95 */ 96 /** 97 * VisuGlExtNodeVectorsPrivate: 98 * 99 * Private fields for #VisuGlExtNodeVectors objects. 100 * 101 * Since: 3.7 102 */ 103 struct _VisuGlExtNodeVectorsPrivate 104 { 105 gboolean dispose_has_run; 106 107 VisuSourceableData *source; 108 109 /* Rendering definitions. */ 110 VisuGlExtNodeVectorsColorScheme colorScheme; 111 float arrow[N_ARROW_DEFS]; 112 float normFactor, scale; 113 VisuGlArrowCentering centering; 114 float translation, addLength; 115 float ratioMin, ratioMinLabel; 116 117 VisuNodeArrayRenderer *renderer; 118 gulong size_sig, col_sig, mat_sig, pop_sig, vis_sig, pos_sig, inc_sig; 119 }; 120 121 enum 122 { 123 PROP_0, 124 NORM_PROP, 125 SCALE_PROP, 126 N_PROP, 127 SOURCE_PROP, 128 MODEL_PROP 129 }; 130 static GParamSpec *_properties[N_PROP]; 131 132 static void visu_gl_ext_node_vectors_dispose(GObject* obj); 133 static void visu_gl_ext_node_vectors_rebuild(VisuGlExt *ext); 134 static void visu_gl_ext_node_vectors_draw(VisuGlExt *vect); 135 static void visu_gl_ext_node_vectors_get_property(GObject* obj, guint property_id, 136 GValue *value, GParamSpec *pspec); 137 static void visu_gl_ext_node_vectors_set_property(GObject* obj, guint property_id, 138 const GValue *value, GParamSpec *pspec); 139 static void visu_sourceable_interface_init(VisuSourceableInterface *iface); 140 static VisuSourceableData** _getSource(VisuSourceable *self); 141 static void _modelChanged(VisuSourceable *self); 142 143 /* Local callbacks. */ 144 static void _setDirty(VisuGlExt *ext); 145 static void onElementSize(VisuElementRenderer *renderer, VisuElementRenderer *element, 146 gfloat extent, VisuGlExtNodeVectors *vect); 147 148 G_DEFINE_TYPE_WITH_CODE(VisuGlExtNodeVectors, visu_gl_ext_node_vectors, VISU_TYPE_GL_EXT, 149 G_ADD_PRIVATE(VisuGlExtNodeVectors) 150 G_IMPLEMENT_INTERFACE(VISU_TYPE_SOURCEABLE, 151 visu_sourceable_interface_init)) 152 153 static void visu_gl_ext_node_vectors_class_init(VisuGlExtNodeVectorsClass *klass) 154 { 155 DBG_fprintf(stderr, "Visu GlExt NodeVectors: creating the class of the object.\n"); 156 /* DBG_fprintf(stderr, " - adding new signals ;\n"); */ 157 158 /* Connect the overloading methods. */ 159 G_OBJECT_CLASS(klass)->dispose = visu_gl_ext_node_vectors_dispose; 160 G_OBJECT_CLASS(klass)->set_property = visu_gl_ext_node_vectors_set_property; 161 G_OBJECT_CLASS(klass)->get_property = visu_gl_ext_node_vectors_get_property; 162 VISU_GL_EXT_CLASS(klass)->rebuild = visu_gl_ext_node_vectors_rebuild; 163 VISU_GL_EXT_CLASS(klass)->draw = visu_gl_ext_node_vectors_draw; 164 165 /** 166 * VisuGlExtNodeVectors::normalisation: 167 * 168 * The normalisation factor, zero to scale to the maximum value, 169 * and positive for an absolute value. 170 * 171 * Since: 3.8 172 */ 173 _properties[NORM_PROP] = g_param_spec_float("normalisation", "Normalisation", 174 "normalisation factor", -1.f, G_MAXFLOAT, 0.f, 175 G_PARAM_READWRITE); 176 /** 177 * VisuGlExtNodeVectors::rendering-size: 178 * 179 * When positive, this will be the rendering size for a normalised 180 * value of 1, if negative, it is a factor used to scale element size. 181 * 182 * Since: 3.8 183 */ 184 _properties[SCALE_PROP] = g_param_spec_float("rendering-size", "Rendering size", 185 "rendering size", -G_MAXFLOAT, G_MAXFLOAT, -2.f, 186 G_PARAM_READWRITE); 187 188 g_object_class_install_properties(G_OBJECT_CLASS(klass), N_PROP, _properties); 189 190 g_object_class_override_property(G_OBJECT_CLASS(klass), SOURCE_PROP, "source"); 191 g_object_class_override_property(G_OBJECT_CLASS(klass), MODEL_PROP, "model"); 192 } 193 static void visu_sourceable_interface_init(VisuSourceableInterface *iface) 194 { 195 iface->getSource = _getSource; 196 iface->modelChanged = _modelChanged; 197 } 198 199 static void visu_gl_ext_node_vectors_init(VisuGlExtNodeVectors *obj) 200 { 201 DBG_fprintf(stderr, "Visu GlExt NodeVectors: initializing a new object (%p).\n", 202 (gpointer)obj); 203 204 obj->priv = visu_gl_ext_node_vectors_get_instance_private(obj); 205 obj->priv->dispose_has_run = FALSE; 206 207 /* Private data. */ 208 visu_sourceable_init(VISU_SOURCEABLE(obj)); 209 obj->priv->colorScheme = VISU_COLOR_ELEMENT; 210 obj->priv->arrow[TAIL_LENGTH] = 0.7f; 211 obj->priv->arrow[TAIL_RADIUS] = 0.1f; 212 obj->priv->arrow[TAIL_NLAT] = 10.f; 213 obj->priv->arrow[HEAD_LENGTH] = 0.3f; 214 obj->priv->arrow[HEAD_RADIUS] = 0.15f; 215 obj->priv->arrow[HEAD_NLAT] = 10.f; 216 obj->priv->normFactor = -1.f; 217 obj->priv->scale = -2.f; 218 obj->priv->centering = VISU_GL_ARROW_BOTTOM_CENTERED; 219 obj->priv->translation = 0.f; 220 obj->priv->addLength = 0.f; 221 obj->priv->ratioMin = 0.f; 222 obj->priv->ratioMinLabel = G_MAXFLOAT; 223 obj->priv->renderer = (VisuNodeArrayRenderer*)0; 224 } 225 226 /* This method can be called several times. 227 It should unref all of its reference to 228 GObjects. */ 229 static void visu_gl_ext_node_vectors_dispose(GObject* obj) 230 { 231 VisuGlExtNodeVectors *vect; 232 233 DBG_fprintf(stderr, "Visu GlExt NodeVectors: dispose object %p.\n", (gpointer)obj); 234 235 vect = VISU_GL_EXT_NODE_VECTORS(obj); 236 if (vect->priv->dispose_has_run) 237 return; 238 vect->priv->dispose_has_run = TRUE; 239 240 /* Disconnect signals. */ 241 visu_sourceable_dispose(VISU_SOURCEABLE(obj)); 242 visu_gl_ext_node_vectors_setNodeRenderer(vect, (VisuNodeArrayRenderer*)0); 243 244 /* Chain up to the parent class */ 245 G_OBJECT_CLASS(visu_gl_ext_node_vectors_parent_class)->dispose(obj); 246 } 247 static void visu_gl_ext_node_vectors_get_property(GObject* obj, guint property_id, 248 GValue *value, GParamSpec *pspec) 249 { 250 VisuGlExtNodeVectors *self = VISU_GL_EXT_NODE_VECTORS(obj); 251 252 DBG_fprintf(stderr, "Extension NodeVectors: get property '%s' -> ", 253 g_param_spec_get_name(pspec)); 254 switch (property_id) 255 { 256 case SOURCE_PROP: 257 g_value_set_string(value, visu_sourceable_getSource(VISU_SOURCEABLE(self))); 258 DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); 259 break; 260 case MODEL_PROP: 261 g_value_set_object(value, visu_sourceable_getNodeModel(VISU_SOURCEABLE(self))); 262 DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); 263 break; 264 case NORM_PROP: 265 g_value_set_float(value, self->priv->normFactor); 266 DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); 267 break; 268 case SCALE_PROP: 269 g_value_set_float(value, self->priv->scale); 270 DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); 271 break; 272 default: 273 /* We don't have any other property... */ 274 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); 275 break; 276 } 277 } 278 static void visu_gl_ext_node_vectors_set_property(GObject* obj, guint property_id, 279 const GValue *value, GParamSpec *pspec) 280 { 281 VisuGlExtNodeVectors *self = VISU_GL_EXT_NODE_VECTORS(obj); 282 283 DBG_fprintf(stderr, "Extension NodeVectors: set property '%s' -> ", 284 g_param_spec_get_name(pspec)); 285 switch (property_id) 286 { 287 case SOURCE_PROP: 288 DBG_fprintf(stderr, "%s.\n", g_value_get_string(value)); 289 visu_sourceable_setSource(VISU_SOURCEABLE(obj), g_value_get_string(value)); 290 break; 291 case MODEL_PROP: 292 DBG_fprintf(stderr, "%p.\n", g_value_get_object(value)); 293 visu_sourceable_setNodeModel(VISU_SOURCEABLE(obj), g_value_get_object(value)); 294 break; 295 case NORM_PROP: 296 DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); 297 visu_gl_ext_node_vectors_setNormalisation(self, g_value_get_float(value)); 298 break; 299 case SCALE_PROP: 300 DBG_fprintf(stderr, "%g.\n", g_value_get_float(value)); 301 visu_gl_ext_node_vectors_setRenderedSize(self, g_value_get_float(value)); 302 break; 303 default: 304 /* We don't have any other property... */ 305 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec); 306 break; 307 } 308 } 309 310 /** 311 * visu_gl_ext_node_vectors_new: 312 * @name: (allow-none): the name to give to the extension. 313 * 314 * Creates a new #VisuGlExt to draw a box. 315 * 316 * Since: 3.7 317 * 318 * Returns: a pointer to the #VisuGlExt it created or 319 * NULL otherwise. 320 */ 321 VisuGlExtNodeVectors* visu_gl_ext_node_vectors_new(const gchar *name) 322 { 323 char *name_ = "Node vectors"; 324 char *description = _("Draw vectors on each nodes."); 325 326 DBG_fprintf(stderr,"Visu GlExt NodeVectors: new object.\n"); 327 328 return g_object_new(VISU_TYPE_GL_EXT_NODE_VECTORS, 329 "name", (name)?name:name_, "label", _(name), 330 "description", description, "nGlObj", 1, 331 "priority", VISU_GL_EXT_PRIORITY_NODE_DECORATIONS, NULL); 332 } 333 334 /** 335 * visu_gl_ext_node_vectors_setNodeRenderer: 336 * @vect: a #VisuGlExtNodeVectors object. 337 * @renderer: a #VisuNodeArrayRenderer object. 338 * 339 * Use the #VisuElementRenderer properties from @renderer to display 340 * vector properties. 341 * 342 * Since: 3.8 343 * 344 * Returns: TRUE if changed. 345 **/ 346 gboolean visu_gl_ext_node_vectors_setNodeRenderer(VisuGlExtNodeVectors *vect, 347 VisuNodeArrayRenderer *renderer) 348 { 349 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 350 351 if (vect->priv->renderer == renderer) 352 return FALSE; 353 354 if (vect->priv->renderer) 355 { 356 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->size_sig); 357 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->col_sig); 358 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->mat_sig); 359 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->pop_sig); 360 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->inc_sig); 361 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->vis_sig); 362 g_signal_handler_disconnect(vect->priv->renderer, vect->priv->pos_sig); 363 g_object_unref(vect->priv->renderer); 364 } 365 vect->priv->renderer = renderer; 366 if (renderer) 367 { 368 g_object_ref(renderer); 369 vect->priv->size_sig = g_signal_connect(renderer, "element-size-changed", 370 G_CALLBACK(onElementSize), vect); 371 vect->priv->col_sig = g_signal_connect_swapped(renderer, "element-notify::color", 372 G_CALLBACK(_setDirty), vect); 373 vect->priv->mat_sig = g_signal_connect_swapped(renderer, "element-notify::material", 374 G_CALLBACK(_setDirty), vect); 375 vect->priv->pop_sig = g_signal_connect_swapped(renderer, "nodes::population-decrease", 376 G_CALLBACK(_setDirty), vect); 377 vect->priv->inc_sig = g_signal_connect_swapped(renderer, "nodes::population-increase", 378 G_CALLBACK(_setDirty), vect); 379 vect->priv->vis_sig = g_signal_connect_swapped(renderer, "nodes::visibility", 380 G_CALLBACK(_setDirty), vect); 381 vect->priv->pos_sig = g_signal_connect_swapped(renderer, "nodes::position", 382 G_CALLBACK(_setDirty), vect); 383 } 384 385 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 386 return TRUE; 387 } 388 static VisuSourceableData** _getSource(VisuSourceable *self) 389 { 390 VisuGlExtNodeVectors *vect = VISU_GL_EXT_NODE_VECTORS(self); 391 392 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(self), (VisuSourceableData**)0); 393 394 return &vect->priv->source; 395 } 396 static void _modelChanged(VisuSourceable *self) 397 { 398 visu_gl_ext_setDirty(VISU_GL_EXT(self), TRUE); 399 } 400 401 /** 402 * visu_gl_ext_node_vectors_setRenderedSize: 403 * @vect: the #VisuGlExtNodeVectors object to modify. 404 * @scale: a floating point value. 405 * 406 * @scale governs how large the node vectors are drawn. For a positive 407 * value, a vector with a normalised size of 1 (see 408 * visu_gl_ext_node_vectors_setNormalisation()) will be drawn with the size of 409 * @scale. For a negative value, a vector of normalised size of 1 will 410 * be drawn with a size of -@scale times the maximum element size (see 411 * visu_node_array_renderer_getMaxElementSize()). 412 * 413 * Since: 3.7 414 * 415 * Returns: TRUE if setting has been changed. 416 **/ 417 gboolean visu_gl_ext_node_vectors_setRenderedSize(VisuGlExtNodeVectors *vect, gfloat scale) 418 { 419 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 420 421 if (vect->priv->scale == scale) 422 return FALSE; 423 424 vect->priv->scale = scale; 425 426 if (vect->priv->renderer && visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))) 427 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 428 return TRUE; 429 } 430 /** 431 * visu_gl_ext_node_vectors_setNormalisation: 432 * @vect: the #VisuGlExtNodeVectors object to modify. 433 * @norm: a floating point value. 434 * 435 * @norm governs how the input node vector field is normalised. With a 436 * positive value, all node vectors will be normalised by @norm. With 437 * a negative value, all node vectors are normalised with respect to 438 * the biggest one. 439 * 440 * Since: 3.7 441 * 442 * Returns: TRUE if setting has been changed. 443 **/ 444 gboolean visu_gl_ext_node_vectors_setNormalisation(VisuGlExtNodeVectors *vect, float norm) 445 { 446 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 447 448 if (vect->priv->normFactor == norm) 449 return FALSE; 450 451 vect->priv->normFactor = norm; 452 453 g_object_notify_by_pspec(G_OBJECT(vect), _properties[NORM_PROP]); 454 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 455 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 456 return TRUE; 457 } 458 /** 459 * visu_gl_ext_node_vectors_setTranslation: 460 * @vect: the #VisuGlExtNodeVectors object to modify. 461 * @trans: a positive floating point value. 462 * 463 * Defines a translation with respect to the center of each node. The 464 * vector is shifted outwards, following the vector direction by an 465 * amount given by the product of @trans and the element size 466 * currently drawn. 467 * 468 * Since: 3.7 469 * 470 * Returns: TRUE if setting has been changed. 471 **/ 472 gboolean visu_gl_ext_node_vectors_setTranslation(VisuGlExtNodeVectors *vect, float trans) 473 { 474 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 475 476 if (vect->priv->translation == trans) 477 return FALSE; 478 479 vect->priv->translation = MAX(0.f, trans); 480 481 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 482 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 483 return TRUE; 484 } 485 /** 486 * visu_gl_ext_node_vectors_setColor: 487 * @vect: the #VisuGlExtNodeVectors object to modify. 488 * @scheme: a value. 489 * 490 * If @scheme is %VISU_COLOR_ELEMENT, the vectors are drawn with the color of the 491 * currently drawn #VisuElement. If @scheme is %VISU_COLOR_BRIGHT, they 492 * are drawn with a highlighted color. If @scheme is 493 * %VISU_COLOR_ORIENTATION, they are drawn with a hue depending onn orientation. 494 * 495 * Since: 3.7 496 * 497 * Returns: TRUE if setting has been changed. 498 **/ 499 gboolean visu_gl_ext_node_vectors_setColor(VisuGlExtNodeVectors *vect, 500 VisuGlExtNodeVectorsColorScheme scheme) 501 { 502 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 503 504 if (vect->priv->colorScheme == scheme) 505 return FALSE; 506 507 vect->priv->colorScheme = scheme; 508 509 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 510 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 511 return TRUE; 512 } 513 /** 514 * visu_gl_ext_node_vectors_setCentering: 515 * @vect: the #VisuGlExtNodeVectors object to modify. 516 * @centering: a #VisuGlArrowCentering id. 517 * 518 * Change how vectors are position with respect to to center of each node. 519 * 520 * Since: 3.7 521 * 522 * Returns: TRUE if setting has been changed. 523 **/ 524 gboolean visu_gl_ext_node_vectors_setCentering(VisuGlExtNodeVectors *vect, 525 VisuGlArrowCentering centering) 526 { 527 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 528 529 if (vect->priv->centering == centering) 530 return FALSE; 531 532 vect->priv->centering = centering; 533 534 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 535 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 536 return TRUE; 537 } 538 /** 539 * visu_gl_ext_node_vectors_setAddLength: 540 * @vect: the #VisuGlExtNodeVectors object to modify. 541 * @addLength: a positive value. 542 * 543 * Change the additional length that is used to draw the tail. 544 * 545 * Since: 3.8 546 * 547 * Returns: TRUE if settings has been changed. 548 **/ 549 gboolean visu_gl_ext_node_vectors_setAddLength(VisuGlExtNodeVectors *vect, gfloat addLength) 550 { 551 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 552 553 if (vect->priv->addLength == addLength) 554 return FALSE; 555 556 vect->priv->addLength = MAX(addLength, 0.f); 557 558 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 559 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 560 return TRUE; 561 } 562 /** 563 * visu_gl_ext_node_vectors_setVectorThreshold: 564 * @vect: the #VisuGlExtNodeVectors object to modify. 565 * @val: a value. 566 * 567 * Vectors are indeed drawn if a threshold value is reach. If @val is 568 * strictly positive, the norm of each vector is compared to @val. If 569 * @val is negative, the normalised [0;1] norm is compared to -@val. 570 * 571 * Since: 3.7 572 * 573 * Returns: TRUE if setting has been changed. 574 **/ 575 gboolean visu_gl_ext_node_vectors_setVectorThreshold(VisuGlExtNodeVectors *vect, float val) 576 { 577 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 578 579 if (vect->priv->ratioMin == val) 580 return FALSE; 581 582 vect->priv->ratioMin = val; 583 584 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 585 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 586 return TRUE; 587 } 588 /** 589 * visu_gl_ext_node_vectors_setLabelThreshold: 590 * @vect: the #VisuGlExtNodeVectors object to modify. 591 * @val: a value. 592 * 593 * Vector norms can be drawn if a threshold value is reach. If @val is 594 * strictly positive, the norm of each vector is compared to @val. If 595 * @val is negative, the normalised [0;1] norm is compared to -@val. 596 * 597 * Since: 3.7 598 * 599 * Returns: TRUE if setting has been changed. 600 **/ 601 gboolean visu_gl_ext_node_vectors_setLabelThreshold(VisuGlExtNodeVectors *vect, float val) 602 { 603 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 604 605 if (vect->priv->ratioMinLabel == val) 606 return FALSE; 607 608 vect->priv->ratioMinLabel = val; 609 610 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 611 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 612 return TRUE; 613 } 614 /** 615 * visu_gl_ext_node_vectors_setArrow: 616 * @vect: the #VisuGlExtNodeVectors object to modify. 617 * @tailLength: the length for the tail part of the vector. 618 * @tailRadius: the radius for the tail part of the vector. 619 * @tailN: the number of polygons to draw the tail part of the vector. 620 * @headLength: the length for the head part of the vector. 621 * @headRadius: the radius for the head part of the vector. 622 * @headN: the number of polygons to draw the head part of the vector. 623 * 624 * Defines the profile of the arrows representing the vectors. 625 * 626 * Since: 3.7 627 * 628 * Returns: TRUE if setting has been changed. 629 **/ 630 gboolean visu_gl_ext_node_vectors_setArrow(VisuGlExtNodeVectors *vect, float tailLength, 631 float tailRadius, guint tailN, 632 float headLength, float headRadius, guint headN) 633 { 634 gboolean diff; 635 float fact; 636 637 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), FALSE); 638 639 diff = FALSE; 640 diff = diff || (vect->priv->arrow[TAIL_LENGTH] != tailLength); 641 diff = diff || (vect->priv->arrow[TAIL_RADIUS] != tailRadius); 642 diff = diff || (vect->priv->arrow[TAIL_NLAT] != tailN); 643 diff = diff || (vect->priv->arrow[HEAD_LENGTH] != headLength); 644 diff = diff || (vect->priv->arrow[HEAD_RADIUS] != headRadius); 645 diff = diff || (vect->priv->arrow[HEAD_NLAT] != headN); 646 if (!diff) 647 return FALSE; 648 649 fact = 1.f / (tailLength + headLength); 650 vect->priv->arrow[TAIL_LENGTH] = tailLength * fact; 651 vect->priv->arrow[TAIL_RADIUS] = tailRadius * fact; 652 vect->priv->arrow[TAIL_NLAT] = tailN; 653 vect->priv->arrow[HEAD_LENGTH] = headLength * fact; 654 vect->priv->arrow[HEAD_RADIUS] = headRadius * fact; 655 vect->priv->arrow[HEAD_NLAT] = headN; 656 657 if (vect->priv->renderer && visu_sourceable_getSource(VISU_SOURCEABLE(vect))) 658 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 659 return TRUE; 660 } 661 662 /** 663 * visu_gl_ext_node_vectors_getScale: 664 * 665 * The forces can be scaled manually or automatically, see 666 * visu_gl_ext_forces_setScale() and visu_rendering_atomic_drawForces(). 667 * 668 * Since: 3.7 669 * 670 * Returns: the scaling factor, -1 if automatic. 671 **/ 672 /* gfloat visu_gl_ext_forces_getScale() */ 673 /* { */ 674 /* return scale; */ 675 /* } */ 676 /** 677 * visu_gl_ext_node_vectors_getNormalisation: 678 * @vect: the #VisuGlExtNodeVectors object to inquire. 679 * 680 * Gets the normalisation factor, see visu_gl_ext_node_vectors_setNormalisation(). 681 * 682 * Since: 3.7 683 * 684 * Returns: the normalisation factor used by @vact. 685 **/ 686 float visu_gl_ext_node_vectors_getNormalisation(VisuGlExtNodeVectors *vect) 687 { 688 g_return_val_if_fail(VISU_IS_GL_EXT_NODE_VECTORS(vect), -1.f); 689 690 return vect->priv->normFactor; 691 } 692 693 /********************/ 694 /* Local callbacks. */ 695 /********************/ 696 static void _setDirty(VisuGlExt *ext) 697 { 698 visu_gl_ext_setDirty(ext, TRUE); 699 } 700 static void onElementSize(VisuElementRenderer *renderer _U_, VisuElementRenderer *element _U_, 701 gfloat extent _U_, VisuGlExtNodeVectors *vect) 702 { 703 if (vect->priv->scale < 0.f || vect->priv->translation > 0.f) 704 visu_gl_ext_setDirty(VISU_GL_EXT(vect), TRUE); 705 } 706 707 /***********/ 708 /* OpenGL. */ 709 /***********/ 710 711 static void visu_gl_ext_node_vectors_draw(VisuGlExt *vect) 712 { 713 VisuNodeArrayRendererIter iter; 714 GLUquadricObj *obj; 715 float fact, scale, eleSize; 716 float rMult, r, sMult, s, l, headLength, tailLength; 717 float xyz[3], dxyz[3], hsl[3], rgba[4]; 718 const gfloat *sph; 719 char distStr[10]; 720 gboolean valid; 721 VisuGlExtNodeVectorsPrivate *priv = VISU_GL_EXT_NODE_VECTORS(vect)->priv; 722 723 glDeleteLists(visu_gl_ext_getGlList(vect), 1); 724 visu_gl_ext_setDirty(vect, FALSE); 725 726 DBG_fprintf(stderr, "Extension Node Vectors: building for nodes %p and vectors %p.\n", 727 (gpointer)priv->renderer, 728 (gpointer)visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))); 729 if (!priv->renderer || !visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))) 730 return; 731 732 obj = gluNewQuadric(); 733 734 /* Normalization factor. */ 735 fact = priv->normFactor; 736 if (fact <= 0.f) 737 fact = visu_node_values_farray_max(VISU_NODE_VALUES_FARRAY(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect)))); 738 fact = 1.f / fact; 739 740 /* Drawing rule for vectors. */ 741 rMult = 1.f; 742 r = 1.f; 743 if (priv->ratioMin <= 0.f) 744 { 745 rMult = fact; 746 r = -1.f; 747 } 748 /* Drawing rule for label. */ 749 sMult = 1.f; 750 s = 1.f; 751 if (priv->ratioMinLabel <= 0.f) 752 { 753 sMult = fact; 754 s = -1.f; 755 } 756 757 /* Maximum representation size. */ 758 scale = priv->scale; 759 if (scale <= 0.f) 760 scale = visu_node_array_renderer_getMaxElementSize(priv->renderer, NULL) * (-scale); 761 762 visu_gl_ext_startDrawing(vect); 763 764 eleSize = 0.f; 765 for (valid = visu_node_array_renderer_iter_new(priv->renderer, &iter, TRUE); 766 valid; valid = visu_node_array_renderer_iter_next(&iter)) 767 { 768 if (!visu_element_getRendered(iter.element)) 769 continue; 770 771 if (priv->colorScheme == VISU_COLOR_ELEMENT) 772 visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_NO_EFFECT); 773 else if (priv->colorScheme == VISU_COLOR_BRIGHT) 774 visu_element_renderer_colorize(iter.renderer, VISU_ELEMENT_RENDERER_HIGHLIGHT); 775 eleSize = visu_element_renderer_getExtent(iter.renderer); 776 777 for(visu_node_array_iterRestartNode(iter.parent.array, &iter.parent); iter.parent.node; 778 visu_node_array_iterNextNode(iter.parent.array, &iter.parent)) 779 { 780 if (!iter.parent.node->rendered) 781 continue; 782 783 sph = visu_node_values_vector_getAtSpherical(VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))), iter.parent.node); 784 if (!sph) 785 continue; 786 787 if (sph[TOOL_MATRIX_SPHERICAL_MODULUS] * rMult <= priv->ratioMin * r) 788 continue; 789 l = sph[TOOL_MATRIX_SPHERICAL_MODULUS] * fact; 790 791 visu_data_getNodePosition(VISU_DATA(iter.parent.array), iter.parent.node, xyz); 792 visu_node_values_vector_getShift(VISU_NODE_VALUES_VECTOR(visu_sourceable_getNodeModel(VISU_SOURCEABLE(vect))), iter.parent.node, dxyz); 793 794 glPushMatrix(); 795 glTranslatef(xyz[0] - dxyz[0], xyz[1] - dxyz[1], xyz[2] - dxyz[2]); 796 /* We draw the arrow. */ 797 if (priv->colorScheme == VISU_COLOR_ORIENTATION) 798 { 799 hsl[2] = 1.f - sph[TOOL_MATRIX_SPHERICAL_THETA] / 180.; 800 hsl[1] = 1.f; 801 hsl[0] = sph[TOOL_MATRIX_SPHERICAL_PHI] / 360.; 802 803 tool_color_convertHSLtoRGB(rgba, hsl); 804 805 rgba[3] = visu_element_renderer_getColor(iter.renderer)->rgba[3]; 806 visu_gl_setColor((VisuGl*)0, visu_element_renderer_getMaterial(iter.renderer), rgba); 807 } 808 glRotated(sph[TOOL_MATRIX_SPHERICAL_PHI], 0, 0, 1); 809 glRotated(sph[TOOL_MATRIX_SPHERICAL_THETA], 0, 1, 0); 810 glTranslated(0.f, 0.f, eleSize * priv->translation); 811 switch (priv->centering) 812 { 813 case (VISU_GL_ARROW_CENTERED): 814 glScalef(scale, scale, scale); 815 tailLength = MAX(0.f, l - priv->arrow[HEAD_LENGTH]); 816 headLength = MIN(l, priv->arrow[HEAD_LENGTH]); 817 break; 818 case (VISU_GL_ARROW_TAIL_CENTERED): 819 glScalef(eleSize, eleSize, eleSize); 820 tailLength = l * scale / eleSize + priv->addLength; 821 headLength = priv->arrow[HEAD_LENGTH]; 822 break; 823 default: 824 glScalef(l * scale, l * scale, l * scale); 825 tailLength = priv->arrow[TAIL_LENGTH]; 826 headLength = priv->arrow[HEAD_LENGTH]; 827 } 828 visu_gl_drawSmoothArrow(obj, priv->centering, 829 tailLength, 830 priv->arrow[TAIL_RADIUS], 831 (guint)priv->arrow[TAIL_NLAT], NULL, 832 headLength, 833 priv->arrow[HEAD_RADIUS], 834 (guint)priv->arrow[HEAD_NLAT], NULL); 835 /* We draw the value. */ 836 if (sph[TOOL_MATRIX_SPHERICAL_MODULUS] * sMult > priv->ratioMinLabel * s) 837 { 838 glRasterPos3f(0.f, 0.f, 0.f); 839 sprintf(distStr, "%6.3f", sph[TOOL_MATRIX_SPHERICAL_MODULUS]); 840 visu_gl_text_drawChars(distStr, VISU_GL_TEXT_NORMAL); 841 } 842 glPopMatrix(); 843 } 844 } 845 846 visu_gl_ext_completeDrawing(vect); 847 848 gluDeleteQuadric(obj); 849 } 850 static void visu_gl_ext_node_vectors_rebuild(VisuGlExt *ext) 851 { 852 DBG_fprintf(stderr, "Visu GlExt NodeVectors: rebuilding vectors %p.\n", (gpointer)ext); 853 visu_gl_text_rebuildFontList(); 854 visu_gl_ext_setDirty(ext, TRUE); 855 visu_gl_ext_node_vectors_draw(ext); 856 } 857