[hkl] fix the test suite due to binoculars new projection signature.
[hkl.git] / hkl3d / hkl3d.cpp
blob900539b0d6e088c4809596c18b91d6607ecbba1c
1 /* This file is part of the hkl3d library.
3 * The hkl library is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * The hkl library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with the hkl library. If not, see <http://www.gnu.org/licenses/>.
16 * Copyright (C) 2010 Synchrotron SOLEIL
17 * L'Orme des Merisiers Saint-Aubin
18 * BP 48 91192 GIF-sur-YVETTE CEDEX
20 * Authors: Picca Frédéric-Emmanuel <picca@synchrotron-soleil.fr>
21 * Oussama Sboui <oussama.sboui@synchrotron-soleil.fr>
24 #include <yaml.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/time.h>
28 #include <unistd.h>
29 #include <libgen.h>
30 #include <g3d/g3d.h>
31 #include <g3d/quat.h>
32 #include <g3d/matrix.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
37 #include "hkl3d.h"
38 #include "hkl-geometry-private.h"
40 #include "btBulletCollisionCommon.h"
41 #include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h"
42 #include "BulletCollision/Gimpact/btGImpactShape.h"
44 #ifdef USE_PARALLEL_DISPATCHER
45 # include "BulletMultiThreaded/SpuGatheringCollisionDispatcher.h"
46 # include "BulletMultiThreaded/PlatformDefinitions.h"
47 # include "BulletMultiThreaded/PosixThreadSupport.h"
48 # include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
49 #endif
51 /***************/
52 /* static part */
53 /***************/
54 static float identity[] = {1, 0, 0, 0,
55 0, 1, 0, 0,
56 0, 0, 1 ,0,
57 0, 0, 0, 1};
59 static void *_hkl3d_malloc(int size, const char *error)
61 void *tmp;
63 tmp = calloc(1, size);
64 if(!tmp){
65 fprintf(stderr, "%s", error);
66 exit(128);
69 return tmp;
71 /* malloc method */
72 #define HKL3D_MALLOC(type) (type *)_hkl3d_malloc(sizeof(type), "Can not allocate memory for a " #type)
74 /***************/
75 /* Hkl3DObject */
76 /***************/
78 static btTriangleMesh *trimesh_from_g3dobject(G3DObject *object)
80 btTriangleMesh *trimesh;
81 float *vertex;
82 GSList *faces;
84 trimesh = new btTriangleMesh();
85 trimesh->preallocateVertices(object->vertex_count);
86 faces = object->faces;
87 vertex = object->vertex_data;
88 while(faces){
89 G3DFace *face;
91 face = (G3DFace*)faces->data;
92 btVector3 vertex0(vertex[3*(face->vertex_indices[0])],
93 vertex[3*(face->vertex_indices[0])+1],
94 vertex[3*(face->vertex_indices[0])+2]);
95 btVector3 vertex1(vertex[3*(face->vertex_indices[1])],
96 vertex[3*(face->vertex_indices[1])+1],
97 vertex[3*(face->vertex_indices[1])+2]);
98 btVector3 vertex2(vertex[3*(face->vertex_indices[2])],
99 vertex[3*(face->vertex_indices[2])+1],
100 vertex[3*(face->vertex_indices[2])+2]);
101 trimesh->addTriangle(vertex0, vertex1, vertex2, true);
103 faces = g_slist_next(faces);
106 return trimesh;
109 static btCollisionShape* shape_from_trimesh(btTriangleMesh *trimesh, int movable)
111 btCollisionShape* shape;
114 * create the bullet shape depending on the static status or not of the piece
115 * static : do not move
116 * movable : connected to a HklGeometry axis.
118 if (movable >= 0){
119 shape = dynamic_cast<btGImpactMeshShape*>(new btGImpactMeshShape(trimesh));
120 shape->setMargin(btScalar(0));
121 shape->setLocalScaling(btVector3(1,1,1));
122 /* maybe usefull for softbodies (useless for now) */
123 (dynamic_cast<btGImpactMeshShape*>(shape))->postUpdate();
124 /* needed for the collision and must be call after the postUpdate (doc) */
125 (dynamic_cast<btGImpactMeshShape*>(shape))->updateBound();
126 }else{
127 shape = dynamic_cast<btBvhTriangleMeshShape*>(new btBvhTriangleMeshShape (trimesh, true));
128 shape->setMargin(btScalar(0));
129 shape->setLocalScaling(btVector3(1,1,1));
132 return shape;
135 static btCollisionObject * btObject_from_shape(btCollisionShape* shape)
137 btCollisionObject *btObject;
139 /* create the Object and add the shape */
140 btObject = new btCollisionObject();
141 btObject->setCollisionShape(shape);
142 btObject->activate(true);
144 return btObject;
148 static Hkl3DObject *hkl3d_object_new(Hkl3DModel *model, G3DObject *object, int id)
150 int i;
151 GSList *faces;
152 G3DMaterial* material;
153 Hkl3DObject *self = NULL;
155 self = HKL3D_MALLOC(Hkl3DObject);
157 /* extract the color from the first face */
158 /* this is usefull for the bullet GL draw method */
159 faces = object->faces;
160 material = ((G3DFace *)faces->data)->material;
162 /* fill the hkl3d object structure. */
163 self->model = model;
164 self->id = id;
165 self->axis_name = strdup(object->name);
166 self->axis = NULL;
167 self->g3d = object;
168 self->meshes = trimesh_from_g3dobject(object);
169 self->btShape = shape_from_trimesh(self->meshes, false);
170 self->btObject = btObject_from_shape(self->btShape);
171 self->color = new btVector3(material->r, material->g, material->b);
172 self->hide = object->hide;
173 self->added = false;
174 self->selected = false;
175 self->movable = false;
178 * if the object already contain a transformation set the Hkl3DObject
179 * transformation with this transformation. Otherwise set it with the
180 * identity
182 if(object->transformation){
183 for(i=0; i<16; i++)
184 self->transformation[i] = object->transformation->matrix[i];
185 }else{
186 /* create one as we requiered it to apply our transformations */
187 object->transformation = g_new0(G3DTransformation, 1);
188 for(i=0; i<16; i++){
189 self->transformation[i] = identity[i];
190 object->transformation->matrix[i] = identity[i];
194 self->is_colliding = false;
196 return self;
199 static void hkl3d_object_free(Hkl3DObject *self)
201 if(!self)
202 return;
204 /* memory leak in libg3d */
205 if(self->g3d && self->g3d->transformation){
206 g_free(self->g3d->transformation);
207 self->g3d->transformation = NULL;
209 if(self->color){
210 delete self->color;
211 self->color = NULL;
213 if(self->btObject){
214 delete self->btObject;
215 self->btObject = NULL;
217 if(self->btShape){
218 delete self->btShape;
219 self->btShape = NULL;
221 if(self->meshes){
222 delete self->meshes;
223 self->meshes = NULL;
225 if(self->axis_name){
226 free(self->axis_name);
227 self->axis_name = NULL;
230 free(self);
233 static void hkl3d_object_set_movable(Hkl3DObject *self, int movable)
235 if(!self)
236 return;
238 if(self->movable != movable){
239 self->movable = movable;
240 delete self->btObject;
241 delete self->btShape;
242 self->btShape = shape_from_trimesh(self->meshes, movable);
243 self->btObject = btObject_from_shape(self->btShape);
247 static void hkl3d_object_set_axis_name(Hkl3DObject *self, const char *name)
249 if(!self || !name || self->axis_name == name)
250 return;
252 if(self->axis_name)
253 free(self->axis_name);
254 self->axis_name = strdup(name);
257 static void matrix_fprintf(FILE *f, const float matrix[])
259 fprintf(f, "transformation : ");
260 for(uint i=0; i<4; ++i){
261 if(i)
262 fprintf(f, " ");
263 for(uint j=0; j<4; ++j){
264 fprintf(f, " %6.3f", matrix[4 * i + j]);
266 fprintf(f, "\n");
270 void hkl3d_object_aabb_get(const Hkl3DObject *self, float from[3], float to[3])
272 btVector3 min, max;
274 self->btShape->getAabb(self->btObject->getWorldTransform(), min, max);
276 from[0] = min.getX();
277 from[1] = min.getY();
278 from[2] = min.getZ();
279 to[0] = max.getX();
280 to[1] = max.getY();
281 to[2] = max.getZ();
284 void hkl3d_object_fprintf(FILE *f, const Hkl3DObject *self)
286 GSList *faces;
287 G3DMaterial* material;
289 faces = self->g3d->faces;
290 material = ((G3DFace *)faces->data)->material;
291 fprintf(f, "id : %d\n", self->id);
292 fprintf(f, "name : %s (%p)\n", self->axis_name, self->axis_name);
293 fprintf(f, "axis : %p\n", self->axis);
294 matrix_fprintf(f, self->transformation);
295 fprintf(f, "btObject : %p\n", self->btObject);
296 fprintf(f, "g3d : %p\n", self->g3d);
297 matrix_fprintf(f, self->g3d->transformation->matrix);
298 fprintf(f, "btShape : %p\n", self->btShape);
299 fprintf(f, "meshes : %p\n", self->meshes);
300 fprintf(f, "color : %f, %f, %f\n", material->r, material->g, material->b);
301 fprintf(f, "is_colliding : %d\n", self->is_colliding);
302 fprintf(f, "hide : %d\n", self->hide);
303 fprintf(f, "added : %d\n", self->added);
304 fprintf(f, "selected : %d\n", self->selected);
307 /**************/
308 /* Hkl3DModel */
309 /**************/
311 static Hkl3DModel *hkl3d_model_new(void)
313 Hkl3DModel *self = NULL;
315 self = HKL3D_MALLOC(Hkl3DModel);
317 self->filename = NULL;
318 self->objects = NULL;
319 self->len = 0;
320 self->g3d = NULL;
322 return self;
325 static void hkl3d_model_free(Hkl3DModel *self)
327 size_t i;
329 if(!self)
330 return;
332 free(self->filename);
333 for(i=0; i<self->len; ++i)
334 hkl3d_object_free(self->objects[i]);
335 free(self->objects);
336 g3d_model_free(self->g3d);
337 free(self);
340 static void hkl3d_model_add_object(Hkl3DModel *self, Hkl3DObject *object)
342 if(!self || !object)
343 return;
345 self->objects = (typeof(self->objects))realloc(self->objects, sizeof(*self->objects) * (self->len + 1));
346 self->objects[self->len++] = object;
349 static void hkl3d_model_delete_object(Hkl3DModel *self, Hkl3DObject *object)
351 size_t i;
353 if(!self || !object)
354 return;
356 if(self != object->model)
357 return;
359 /* find the index of the object */
360 for(i=0; self->objects[i] != object; ++i);
362 hkl3d_object_free(object);
363 self->len--;
364 /* move all above objects of 1 position */
365 if(i < self->len)
366 memmove(object, object + 1, sizeof(object) * (self->len - i));
369 void hkl3d_model_fprintf(FILE *f, const Hkl3DModel *self)
371 fprintf(f, "config (%zd):\n", self->len);
372 for(size_t i=0; i<self->len; ++i)
373 hkl3d_object_fprintf(f, self->objects[i]);
377 * Initialize the bullet collision environment.
378 * create the Hkl3DObjects
379 * create the Hkl3DConfig
381 static Hkl3DModel *hkl3d_model_new_from_file(const char *filename)
383 G3DModel *model;
384 Hkl3DModel *self = NULL;
385 GSList *objects; /* lets iterate from the first object. */
386 G3DContext *context;
388 if(!filename)
389 return NULL;
391 /* load the model from the file */
392 context = g3d_context_new();
393 model = g3d_model_load_full(context, filename, 0);
394 g3d_context_free(context);
395 if(!model)
396 return NULL;
397 self = hkl3d_model_new();
399 self->filename = strdup(filename);
400 self->g3d = model;
402 /* create all the attached Hkl3DObjects */
403 objects = model->objects;
404 while(objects){
405 G3DObject *object;
407 object = (G3DObject*)objects->data;
408 if(object->vertex_count){
409 int id;
410 Hkl3DObject *hkl3dObject;
412 id = g_slist_index(model->objects, object);
413 hkl3dObject = hkl3d_object_new(self, object, id);
415 /* remembers objects to avoid memory leak */
416 hkl3d_model_add_object(self, hkl3dObject);
418 objects = g_slist_next(objects);
420 return self;
423 /***************/
424 /* Hkl3DConfig */
425 /***************/
427 static Hkl3DConfig* hkl3d_config_new(void)
429 Hkl3DConfig* self = NULL;
431 self = (Hkl3DConfig*)malloc(sizeof(Hkl3DConfig));
432 if(!self)
433 return NULL;
435 self->models = NULL;
436 self->len = 0;
438 return self;
441 static void hkl3d_config_free(Hkl3DConfig *self)
443 if(!self)
444 return;
446 for(size_t i=0; i<self->len; ++i)
447 hkl3d_model_free(self->models[i]);
448 free(self->models);
449 free(self);
452 static void hkl3d_config_add_model(Hkl3DConfig *self, Hkl3DModel *model)
454 self->models = (typeof(self->models))realloc(self->models, sizeof(*self->models) * (self->len + 1));
455 self->models[self->len++] = model;
458 void hkl3d_config_fprintf(FILE *f, const Hkl3DConfig *self)
460 fprintf(f, "models (%zd):\n", self->len);
461 for(size_t i=0; i<self->len; ++i)
462 hkl3d_model_fprintf(f, self->models[i]);
465 /**************/
466 /* Hkl3DStats */
467 /**************/
469 double hkl3d_stats_get_collision_ms(const Hkl3DStats *self)
471 return self->collision.tv_sec*1000. + self->collision.tv_usec/1000.;
474 void hkl3d_stats_fprintf(FILE *f, const Hkl3DStats *self)
476 fprintf(f, "transformation : %f ms collision : %f ms \n",
477 self->transformation.tv_sec*1000. + self->transformation.tv_usec/1000.,
478 hkl3d_stats_get_collision_ms(self));
481 /*************/
482 /* Hkl3DAxis */
483 /*************/
485 static Hkl3DAxis *hkl3d_axis_new(void)
487 Hkl3DAxis *self = NULL;
489 self = HKL3D_MALLOC(Hkl3DAxis);
491 self->objects = NULL; /* do not own the objects */
492 self->len = 0;
494 return self;
497 static void hkl3d_axis_free(Hkl3DAxis *self)
499 if(!self)
500 return;
502 free(self->objects);
503 free(self);
506 /* should be optimized (useless if the Hkl3DObject had a connection with the Hkl3DAxis */
507 static void hkl3d_axis_attach_object(Hkl3DAxis *self, Hkl3DObject *object)
509 object->axis = self;
510 self->objects = (Hkl3DObject **)realloc(self->objects, sizeof(*self->objects) * (self->len + 1));
511 self->objects[self->len++] = object;
514 /* should be optimized (useless if the Hkl3DObject had a connection with the Hkl3DAxis */
515 static void hkl3d_axis_detach_object(Hkl3DAxis *self, Hkl3DObject *object)
517 size_t i;
519 if(!self || !object)
520 return;
522 if(self != object->axis)
523 return;
525 /* find the index of the object in the object list */
526 for(i=0; self->objects[i] != object; ++i);
528 object->axis = NULL;
529 /* move all above objects of 1 position */
530 self->len--;
531 if(i < self->len)
532 memmove(object, object+1, sizeof(object) * (self->len - i));
535 static void hkl3d_axis_fprintf(FILE *f, const Hkl3DAxis *self)
537 if(!f || !self)
538 return;
540 fprintf(f, "Axis len : %zd\n", self->len);
541 for(size_t i=0; i<self->len; ++i)
542 hkl3d_object_fprintf(f, self->objects[i]);
545 /*****************/
546 /* Hkl3DGeometry */
547 /*****************/
549 static Hkl3DGeometry *hkl3d_geometry_new(HklGeometry *geometry)
551 uint i;
552 Hkl3DGeometry *self = NULL;
554 self = HKL3D_MALLOC(Hkl3DGeometry);
556 self->geometry = geometry;
557 self->axes = (Hkl3DAxis **)malloc(darray_size(geometry->axes) * sizeof(*self->axes));
559 for(i=0; i<darray_size(geometry->axes); ++i)
560 self->axes[i] = hkl3d_axis_new();
562 return self;
565 static void hkl3d_geometry_free(Hkl3DGeometry *self)
567 uint i;
569 if(!self)
570 return;
572 for(i=0; i<darray_size(self->geometry->axes); ++i)
573 hkl3d_axis_free(self->axes[i]);
574 free(self->axes);
575 free(self);
578 static void hkl3d_geometry_apply_transformations(Hkl3DGeometry *self)
580 HklHolder **holder;
582 darray_foreach(holder, self->geometry->holders){
583 size_t j;
584 btQuaternion btQ(0, 0, 0, 1);
586 size_t len = (*holder)->config->len;
587 for(j=0; j<len; j++){
588 size_t k;
589 size_t idx = (*holder)->config->idx[j];
590 const HklQuaternion *q = hkl_parameter_quaternion_get(darray_item(self->geometry->axes, idx));
591 G3DMatrix G3DM[16];
593 /* conversion beetween hkl -> bullet coordinates */
594 btQ *= btQuaternion(-q->data[1],
595 q->data[3],
596 q->data[2],
597 q->data[0]);
599 /* move each object connected to that hkl Axis. */
600 /* apply the quaternion transformation to the bullet object */
601 /* use the bullet library to compute the OpenGL matrix */
602 /* apply this matrix to the G3DObject for the visualisation */
603 for(k=0; k<self->axes[idx]->len; ++k){
604 self->axes[idx]->objects[k]->btObject->getWorldTransform().setRotation(btQ);
605 self->axes[idx]->objects[k]->btObject->getWorldTransform().getOpenGLMatrix( G3DM );
606 memcpy(self->axes[idx]->objects[k]->g3d->transformation->matrix,
607 &G3DM[0], sizeof(G3DM));
613 static void hkl3d_geometry_fprintf(FILE *f, const Hkl3DGeometry *self)
615 if(!f || !self)
616 return;
618 fprintf(f, "Hkl3DGeometry : \n");
619 hkl_geometry_fprintf(f, self->geometry);
620 for(size_t i=0; i<darray_size(self->geometry->axes); ++i)
621 hkl3d_axis_fprintf(f, self->axes[i]);
624 static Hkl3DAxis *hkl3d_geometry_axis_get(Hkl3DGeometry *self, const char *name)
626 for(size_t i=0; i<darray_size(self->geometry->axes); ++i){
627 if (!strcmp(hkl_parameter_name_get(darray_item(self->geometry->axes, i)),
628 name))
629 return self->axes[i];
631 return NULL;
634 /*********/
635 /* HKL3D */
636 /*********/
638 static void hkl3d_apply_transformations(Hkl3D *self)
640 struct timeval debut, fin;
642 /* set the right transformation of each objects and get numbers */
643 gettimeofday(&debut, NULL);
644 hkl3d_geometry_apply_transformations(self->geometry);
645 gettimeofday(&fin, NULL);
646 timersub(&fin, &debut, &self->stats.transformation);
649 void hkl3d_connect_all_axes(Hkl3D *self)
651 /* connect use the axes names */
652 for(size_t i=0;i<self->config->len;i++)
653 for(size_t j=0;j<self->config->models[i]->len;j++)
654 hkl3d_connect_object_to_axis(self,
655 self->config->models[i]->objects[j],
656 self->config->models[i]->objects[j]->axis_name);
660 * Hkl3D::Hkl3D:
661 * @filename:
662 * @geometry:
666 * Returns:
668 Hkl3D *hkl3d_new(const char *filename, HklGeometry *geometry)
670 Hkl3D *self = NULL;
672 self = HKL3D_MALLOC(Hkl3D);
674 self->geometry = hkl3d_geometry_new(geometry);
675 self->config = hkl3d_config_new();
676 self->model= g3d_model_new();
678 /* initialize the bullet part */
679 self->_btCollisionConfiguration = new btDefaultCollisionConfiguration();
681 #ifdef USE_PARALLEL_DISPATCHER
682 int maxNumOutstandingTasks = 2;
683 PosixThreadSupport::ThreadConstructionInfo constructionInfo("collision",
684 processCollisionTask,
685 createCollisionLocalStoreMemory,
686 maxNumOutstandingTasks);
687 self->_btThreadSupportInterface = new PosixThreadSupport(constructionInfo);
688 self->_btDispatcher = new SpuGatheringCollisionDispatcher(self->_btThreadSupportInterface,
689 maxNumOutstandingTasks,
690 self->_btCollisionConfiguration);
691 #else
692 self->_btDispatcher = new btCollisionDispatcher(self->_btCollisionConfiguration);
693 #endif
694 btGImpactCollisionAlgorithm::registerAlgorithm(self->_btDispatcher);
696 btVector3 worldAabbMin(-1000,-1000,-1000);
697 btVector3 worldAabbMax( 1000, 1000, 1000);
699 self->_btBroadphase = new btAxisSweep3(worldAabbMin, worldAabbMax);
701 self->_btWorld = new btCollisionWorld(self->_btDispatcher,
702 self->_btBroadphase,
703 self->_btCollisionConfiguration);
705 self->filename = filename;
706 if (filename)
707 hkl3d_load_config(self, filename);
709 return self;
712 void hkl3d_free(Hkl3D *self)
714 /* remove all objects from the collision world */
715 for(size_t i=0; i<self->config->len; ++i)
716 for(size_t j=0; j<self->config->models[i]->len; ++j)
717 if(self->config->models[i]->objects[j]->added)
718 self->_btWorld->removeCollisionObject(self->config->models[i]->objects[j]->btObject);
720 hkl3d_geometry_free(self->geometry);
721 hkl3d_config_free(self->config);
723 if (self->_btWorld)
724 delete self->_btWorld;
725 if (self->_btBroadphase)
726 delete self->_btBroadphase;
727 if (self->_btDispatcher)
728 delete self->_btDispatcher;
729 #ifdef USE_PARALLEL_DISPATCHER
730 if (self->_btThreadSupportInterface){
731 /* delete _btThreadSupportInterface; */
732 /* _btThreadSupportInterface = 0; */
734 #endif
735 if (self->_btCollisionConfiguration)
736 delete self->_btCollisionConfiguration;
737 g_free(self->model); /* do not use g3d_model_free as it is juste a container for all config->model */
739 free(self);
742 Hkl3DModel *hkl3d_add_model_from_file(Hkl3D *self,
743 const char *filename, const char *directory)
745 int current;
746 Hkl3DModel *model = NULL;
747 int res;
749 /* first set the current directory using the directory
750 * parameter. Maybe using openat should be a better solution
751 * in the hkl3d_model_new_from_file */
752 current = open(".", O_RDONLY);
753 if (current < 0)
754 return NULL;
755 res = chdir(directory);
756 if(res < 0)
757 goto close_current;
759 model = hkl3d_model_new_from_file(filename);
760 if(model){
761 /* we can not display two different models with the current g3dviewer code */
762 /* so concatenate this loaded model with the one of hkl3d */
763 self->model->objects = g_slist_concat(self->model->objects, model->g3d->objects);
764 self->model->materials = g_slist_concat(self->model->materials, model->g3d->materials);
766 /* update the Hkl3D internals from the model */
767 hkl3d_config_add_model(self->config, model);
769 /* restore the current directory */
770 res = fchdir(current);
772 return model;
774 close_current:
775 close(current);
776 return NULL;
779 /* check that the axis name is really available in the Geometry */
780 /* if axis name not valid make the object static object->name = NULL */
781 /* ok so check if the axis was already connected or not */
782 /* if already connected check if it was a different axis do the job */
783 /* if not yet connected do the job */
784 /* fill movingCollisionObject and movingG3DObjects vectors for transformations */
785 void hkl3d_connect_object_to_axis(Hkl3D *self, Hkl3DObject *object, const char *name)
787 Hkl3DAxis *axis3d = hkl3d_geometry_axis_get(self->geometry, name);
788 if (!object->movable){
789 if(axis3d){ /* static -> movable */
790 self->_btWorld->removeCollisionObject(object->btObject);
791 hkl3d_object_set_movable(object, true);
792 self->_btWorld->addCollisionObject(object->btObject);
793 object->added = true;
794 hkl3d_axis_attach_object(axis3d, object);
796 }else{
797 if(!axis3d){ /* movable -> static */
798 self->_btWorld->removeCollisionObject(object->btObject);
799 hkl3d_object_set_movable(object, false);
800 self->_btWorld->addCollisionObject(object->btObject);
801 object->added = true;
802 }else{ /* movable -> movable */
803 if(strcmp(object->axis_name, name)){ /* not the same axis */
804 hkl3d_axis_detach_object(object->axis, object);
805 hkl3d_axis_attach_object(axis3d, object);
809 hkl3d_object_set_axis_name(object, name);
812 void hkl3d_load_config(Hkl3D *self, const char *filename)
814 int j = 0;
815 int l;
816 int endEvent = 0;
817 yaml_parser_t parser;
818 yaml_event_t input_event;
819 FILE *file;
820 char *dirc;
821 char *dir;
822 Hkl3DModel *config = NULL;
824 /* Clear the objects. */
825 memset(&parser, 0, sizeof(parser));
826 memset(&input_event, 0, sizeof(input_event));
828 file = fopen(filename, "rb");
829 if (!file){
830 fprintf(stderr, "Could not open the %s config file\n", filename);
831 return;
834 if (!yaml_parser_initialize(&parser))
835 fprintf(stderr, "Could not initialize the parser object\n");
836 yaml_parser_set_input_file(&parser, file);
838 /* compute the dirname of the config file as all model files */
839 /* will be relative to this directory */
840 dirc = strdup(filename);
841 dir = dirname(dirc);
843 while(!endEvent){
844 /* Get the next event. */
845 yaml_parser_parse(&parser, &input_event);
847 /* Check if this is the stream end. */
848 if(input_event.type == YAML_STREAM_END_EVENT)
849 endEvent = 1;
850 if(input_event.type == YAML_DOCUMENT_START_EVENT){
851 j=0;
852 /* skip 4 events */
853 // DOCUMENT-START
854 // SEQUENCE-START
855 // MAPPING-START
856 // SCALAR fileName key
857 for(l=0;l<4;l++){
858 yaml_event_delete(&input_event);
859 yaml_parser_parse(&parser, &input_event);
862 /* the add form file method create a default Hkl3DModel and add it to the HKL3D */
863 /* we just need to update this config with the values from the configuration file */
864 config = hkl3d_add_model_from_file(self, (const char *)input_event.data.scalar.value, dir);
865 /* skip 3 events */
866 // SCALAR objects key
867 // SEQUENCE-START
868 // MAPPING-START
869 for(l=0;l<3;l++){
870 yaml_event_delete(&input_event);
871 yaml_parser_parse(&parser, &input_event);
875 if((input_event.type==YAML_MAPPING_START_EVENT)&& config){
876 j++;
877 /* skip 2 events */
878 // MAPPING-START
879 // SCALAR iD key
880 for(l=0;l<2;l++){
881 yaml_event_delete(&input_event);
882 yaml_parser_parse(&parser, &input_event);
885 /* get the object id */
886 config->objects[j-1]->id = atoi((const char *)input_event.data.scalar.value);
888 /* skip 2 more events */
889 // SCALAR valueId
890 // SCALAR Name key
891 for(l=0;l<2;l++){
892 yaml_event_delete(&input_event);
893 yaml_parser_parse(&parser, &input_event);
896 /* get the name of the object from the config file */
897 hkl3d_object_set_axis_name(config->objects[j-1], (const char *)input_event.data.scalar.value);
898 /* skip 3 events */
899 // SCALAR NameValue
900 // SCALAR transformation key
901 // SEQUENCE-START
902 for(l=0;l<3;l++){
903 yaml_event_delete(&input_event);
904 yaml_parser_parse(&parser, &input_event);
907 /* get the 16 values of the transformation */
908 for(l=0;l<16;l++){
909 config->objects[j-1]->transformation[l] = atof((const char *)input_event.data.scalar.value);
910 yaml_event_delete(&input_event);
911 yaml_parser_parse(&parser, &input_event);
914 /* skip 2 events */
915 // SEQUENCE-END
916 // SCALAR hide key
917 for(l=0;l<2;l++){
918 yaml_event_delete(&input_event);
919 yaml_parser_parse(&parser, &input_event);
922 /* get the hide value */
923 config->objects[j-1]->hide = strcmp((const char *)input_event.data.scalar.value, "no");
924 config->objects[j-1]->g3d->hide = config->objects[j-1]->hide;
926 yaml_event_delete(&input_event);
929 free(dirc);
930 yaml_parser_delete(&parser);
931 fclose(file);
933 /* now that everythings goes fine we can save the filename */
934 self->filename = filename;
936 hkl3d_connect_all_axes(self);
939 void hkl3d_save_config(Hkl3D *self, const char *filename)
941 for(size_t i=0; i<self->config->len; i++){
942 char number[64];
943 int properties1, key1, value1,seq0;
944 int root;
945 time_t now;
946 yaml_emitter_t emitter;
947 yaml_document_t output_document;
948 yaml_event_t output_event;
949 FILE * file;
951 memset(&emitter, 0, sizeof(emitter));
952 memset(&output_document, 0, sizeof(output_document));
953 memset(&output_event, 0, sizeof(output_event));
955 if (!yaml_emitter_initialize(&emitter))
956 fprintf(stderr, "Could not inialize the emitter object\n");
958 /* Set the emitter parameters */
959 file = fopen(filename, "a+");
960 if(!file){
961 fprintf(stderr, "Could not open the config file %s to save\n", filename);
962 return;
964 yaml_emitter_set_output_file(&emitter, file);
965 yaml_emitter_open(&emitter);
967 /* Create an output_document object */
968 if (!yaml_document_initialize(&output_document, NULL, NULL, NULL, 0, 0))
969 fprintf(stderr, "Could not create a output_document object\n");
971 /* Create the root of the config file */
972 time(&now);
973 root = yaml_document_add_sequence(&output_document,
974 (yaml_char_t *)ctime(&now),
975 YAML_BLOCK_SEQUENCE_STYLE);
977 /* create the property of the root sequence */
978 properties1 = yaml_document_add_mapping(&output_document,
979 (yaml_char_t *)YAML_MAP_TAG,
980 YAML_BLOCK_MAPPING_STYLE);
982 yaml_document_append_sequence_item(&output_document, root, properties1);
984 /* add the map key1 : value1 to the property */
985 key1 = yaml_document_add_scalar(&output_document,
986 NULL,
987 (yaml_char_t *)"FileName",
989 YAML_PLAIN_SCALAR_STYLE);
990 value1 = yaml_document_add_scalar(&output_document,
991 NULL,
992 (yaml_char_t *)self->config->models[i]->filename,
994 YAML_PLAIN_SCALAR_STYLE);
995 yaml_document_append_mapping_pair(&output_document, properties1, key1, value1);
997 /* add the map key1 : seq0 to the first property */
998 key1 = yaml_document_add_scalar(&output_document,
999 NULL,
1000 (yaml_char_t *)"Objects",
1002 YAML_PLAIN_SCALAR_STYLE);
1003 /* create the sequence of objects */
1004 seq0 = yaml_document_add_sequence(&output_document,
1005 (yaml_char_t *)YAML_SEQ_TAG,
1006 YAML_BLOCK_SEQUENCE_STYLE);
1007 for(size_t j=0; j<self->config->models[i]->len; j++){
1008 int k;
1009 int properties;
1010 int key;
1011 int value;
1012 int seq1;
1014 properties = yaml_document_add_mapping(&output_document,
1015 (yaml_char_t *)YAML_MAP_TAG,
1016 YAML_BLOCK_MAPPING_STYLE);
1017 yaml_document_append_sequence_item(&output_document,seq0, properties);
1019 key = yaml_document_add_scalar(&output_document,
1020 NULL,
1021 (yaml_char_t *)"Id", -1,
1022 YAML_PLAIN_SCALAR_STYLE);
1024 sprintf(number, "%d", self->config->models[i]->objects[j]->id);
1025 value = yaml_document_add_scalar(&output_document,
1026 NULL,
1027 (yaml_char_t *)number,
1029 YAML_PLAIN_SCALAR_STYLE);
1030 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1032 key = yaml_document_add_scalar(&output_document,
1033 NULL,
1034 (yaml_char_t *)"Name",
1036 YAML_PLAIN_SCALAR_STYLE);
1037 value = yaml_document_add_scalar(&output_document,
1038 NULL,
1039 (yaml_char_t *)self->config->models[i]->objects[j]->axis_name,
1041 YAML_PLAIN_SCALAR_STYLE);
1042 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1044 key = yaml_document_add_scalar(&output_document,
1045 NULL,
1046 (yaml_char_t *)"Transformation",
1048 YAML_PLAIN_SCALAR_STYLE);
1049 seq1 = yaml_document_add_sequence(&output_document,
1050 (yaml_char_t *)YAML_SEQ_TAG,
1051 YAML_FLOW_SEQUENCE_STYLE);
1052 yaml_document_append_mapping_pair(&output_document,properties, key, seq1);
1053 for(k=0; k<16; k++){
1054 sprintf(number, "%f", self->config->models[i]->objects[j]->transformation[k]);
1055 value = yaml_document_add_scalar(&output_document,
1056 NULL,
1057 (yaml_char_t *)number,
1059 YAML_PLAIN_SCALAR_STYLE);
1060 yaml_document_append_sequence_item(&output_document,seq1,value);
1063 key = yaml_document_add_scalar(&output_document,
1064 NULL,
1065 (yaml_char_t *)"Hide",
1067 YAML_PLAIN_SCALAR_STYLE);
1068 if(self->config->models[i]->objects[j]->hide)
1069 value = yaml_document_add_scalar(&output_document,
1070 NULL,
1071 (yaml_char_t *)"yes",
1073 YAML_PLAIN_SCALAR_STYLE);
1074 else
1075 value = yaml_document_add_scalar(&output_document,
1076 NULL,
1077 (yaml_char_t *)"no",
1079 YAML_PLAIN_SCALAR_STYLE);
1080 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1082 yaml_document_append_mapping_pair(&output_document, properties1, key1, seq0);
1084 /* flush the document */
1085 yaml_emitter_dump(&emitter, &output_document);
1086 fclose(file);
1088 yaml_document_delete(&output_document);
1089 yaml_emitter_delete(&emitter);
1094 * Hkl3D::hide_object:
1096 * update the visibility of an Hkl3DObject in the bullet world
1097 * add or remove the object from the _btWorld depending on the hide
1098 * member of the object.
1100 void hkl3d_hide_object(Hkl3D *self, Hkl3DObject *object, int hide)
1102 /* first update the G3DObject */
1103 object->hide = hide;
1104 object->g3d->hide = hide;
1105 if(object->hide){
1106 if (object->added){
1107 self->_btWorld->removeCollisionObject(object->btObject);
1108 object->added = false;
1110 }else{
1111 if(!object->added){
1112 self->_btWorld->addCollisionObject(object->btObject);
1113 object->added = true;
1118 /* remove an object from the model */
1119 void hkl3d_remove_object(Hkl3D *self, Hkl3DObject *object)
1121 hkl3d_hide_object(self, object, TRUE);
1122 hkl3d_axis_detach_object(object->axis, object);
1124 /* now remove the G3DObject from the model */
1125 self->model->objects = g_slist_remove(self->model->objects, object->g3d);
1126 hkl3d_model_delete_object(object->model, object);
1130 int hkl3d_is_colliding(Hkl3D *self)
1132 int numManifolds;
1133 struct timeval debut, fin;
1135 /* apply geometry transformation */
1136 hkl3d_apply_transformations(self);
1138 /* perform the collision detection and get numbers */
1139 gettimeofday(&debut, NULL);
1140 if(self->_btWorld){
1141 self->_btWorld->performDiscreteCollisionDetection();
1142 self->_btWorld->updateAabbs();
1144 gettimeofday(&fin, NULL);
1145 timersub(&fin, &debut, &self->stats.collision);
1147 numManifolds = self->_btDispatcher->getNumManifolds();
1149 /* update Hkl3DObject collision from manifolds */
1150 for(size_t i=0; i<self->config->len; i++){
1151 for(size_t j=0; j<self->config->models[i]->len; j++){
1152 Hkl3DObject *object = self->config->models[i]->objects[j];
1153 object->is_colliding = FALSE;
1154 for(int k=0; k<numManifolds; ++k){
1155 btPersistentManifold *manifold = self->_btDispatcher->getManifoldByIndexInternal(k);
1156 object->is_colliding |= object->btObject == manifold->getBody0();
1157 object->is_colliding |= object->btObject == manifold->getBody1();
1162 return numManifolds != 0;
1166 * Hkl3D::get_bounding_boxes:
1167 * @min:
1168 * @max:
1170 * get the bounding boxes of the current world from the bullet internals.
1172 void hkl3d_get_bounding_boxes(Hkl3D *self,
1173 struct btVector3 *min, struct btVector3 *max)
1175 self->_btWorld->getBroadphase()->getBroadphaseAabb(*min, *max);
1178 int hkl3d_get_nb_manifolds(Hkl3D *self)
1180 return self->_btDispatcher->getNumManifolds();
1183 int hkl3d_get_nb_contacts(Hkl3D *self, int manifold)
1185 return self->_btDispatcher->getManifoldByIndexInternal(manifold)->getNumContacts();
1188 void hkl3d_get_collision_coordinates(Hkl3D *self, int manifold, int contact,
1189 double *xa, double *ya, double *za,
1190 double *xb, double *yb, double *zb)
1192 btPersistentManifold *contactManifold;
1194 contactManifold = self->_btDispatcher->getManifoldByIndexInternal(manifold);
1195 btManifoldPoint & pt = contactManifold->getContactPoint(contact);
1196 btVector3 ptA = pt.getPositionWorldOnA();
1197 btVector3 ptB = pt.getPositionWorldOnB();
1199 *xa = ptA.x();
1200 *ya = ptA.y();
1201 *za = ptA.z();
1202 *xb = ptB.x();
1203 *yb = ptB.y();
1204 *zb = ptB.z();
1207 void hkl3d_fprintf(FILE *f, const Hkl3D *self)
1210 fprintf(f, "filename : %s\n", self->filename);
1211 hkl3d_geometry_fprintf(f, self->geometry);
1212 fprintf(f, "\n");
1213 fprintf(f, "model : %p\n", self->model);
1214 hkl3d_stats_fprintf(f, &self->stats);
1215 hkl3d_config_fprintf(f, self->config);
1217 fprintf(f, "_btCollisionConfiguration : %p\n", self->_btCollisionConfiguration);
1218 fprintf(f, "_btBroadphase : %p\n", self->_btBroadphase);
1219 fprintf(f, "_btWorld : %p\n", self->_btWorld);
1220 fprintf(f, "_btDispatcher : %p\n", self->_btDispatcher);
1221 #ifdef USE_PARALLEL_DISPATCHER
1222 fprintf(f, "_btThreadSupportInterface : %p\n", self->_btThreadSupportInterface);
1223 #endif