[contrib][haskell] Hkl.Xrd.OneD
[hkl.git] / hkl3d / hkl3d.cpp
blobde0d79e1e7378e1281db785761fb715061bf2a47
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 /***************/
55 static float identity[] = {1, 0, 0, 0,
56 0, 1, 0, 0,
57 0, 0, 1 ,0,
58 0, 0, 0, 1};
60 static void *_hkl3d_malloc(int size, const char *error)
62 void *tmp;
64 tmp = calloc(1, size);
65 if(!tmp){
66 fprintf(stderr, "%s", error);
67 exit(128);
70 return tmp;
72 /* malloc method */
73 #define HKL3D_MALLOC(type) (type *)_hkl3d_malloc(sizeof(type), "Can not allocate memory for a " #type)
75 /***************/
76 /* Hkl3DObject */
77 /***************/
79 static btTriangleMesh *trimesh_from_g3dobject(G3DObject *object)
81 btTriangleMesh *trimesh;
82 float *vertex;
83 GSList *faces;
85 trimesh = new btTriangleMesh();
86 trimesh->preallocateVertices(object->vertex_count);
87 faces = object->faces;
88 vertex = object->vertex_data;
89 while(faces){
90 G3DFace *face;
92 face = (G3DFace*)faces->data;
93 btVector3 vertex0(vertex[3*(face->vertex_indices[0])],
94 vertex[3*(face->vertex_indices[0])+1],
95 vertex[3*(face->vertex_indices[0])+2]);
96 btVector3 vertex1(vertex[3*(face->vertex_indices[1])],
97 vertex[3*(face->vertex_indices[1])+1],
98 vertex[3*(face->vertex_indices[1])+2]);
99 btVector3 vertex2(vertex[3*(face->vertex_indices[2])],
100 vertex[3*(face->vertex_indices[2])+1],
101 vertex[3*(face->vertex_indices[2])+2]);
102 trimesh->addTriangle(vertex0, vertex1, vertex2, true);
104 faces = g_slist_next(faces);
107 return trimesh;
110 static btCollisionShape* shape_from_trimesh(btTriangleMesh *trimesh, int movable)
112 btCollisionShape* shape;
115 * create the bullet shape depending on the static status or not of the piece
116 * static : do not move
117 * movable : connected to a HklGeometry axis.
119 if (movable >= 0){
120 shape = dynamic_cast<btGImpactMeshShape*>(new btGImpactMeshShape(trimesh));
121 shape->setMargin(btScalar(0));
122 shape->setLocalScaling(btVector3(1,1,1));
123 /* maybe usefull for softbodies (useless for now) */
124 (dynamic_cast<btGImpactMeshShape*>(shape))->postUpdate();
125 /* needed for the collision and must be call after the postUpdate (doc) */
126 (dynamic_cast<btGImpactMeshShape*>(shape))->updateBound();
127 }else{
128 shape = dynamic_cast<btBvhTriangleMeshShape*>(new btBvhTriangleMeshShape (trimesh, true));
129 shape->setMargin(btScalar(0));
130 shape->setLocalScaling(btVector3(1,1,1));
133 return shape;
136 static btCollisionObject * btObject_from_shape(btCollisionShape* shape)
138 btCollisionObject *btObject;
140 /* create the Object and add the shape */
141 btObject = new btCollisionObject();
142 btObject->setCollisionShape(shape);
143 btObject->activate(true);
145 return btObject;
149 static Hkl3DObject *hkl3d_object_new(Hkl3DModel *model, G3DObject *object, int id)
151 int i;
152 GSList *faces;
153 G3DMaterial* material;
154 Hkl3DObject *self = NULL;
156 self = HKL3D_MALLOC(Hkl3DObject);
158 /* extract the color from the first face */
159 /* this is usefull for the bullet GL draw method */
160 faces = object->faces;
161 material = ((G3DFace *)faces->data)->material;
163 /* fill the hkl3d object structure. */
164 self->model = model;
165 self->id = id;
166 self->axis_name = strdup(object->name);
167 self->axis = NULL;
168 self->g3d = object;
169 self->meshes = trimesh_from_g3dobject(object);
170 self->btShape = shape_from_trimesh(self->meshes, false);
171 self->btObject = btObject_from_shape(self->btShape);
172 self->color = new btVector3(material->r, material->g, material->b);
173 self->hide = object->hide;
174 self->added = false;
175 self->selected = false;
176 self->movable = false;
179 * if the object already contain a transformation set the Hkl3DObject
180 * transformation with this transformation. Otherwise set it with the
181 * identity
183 if(object->transformation){
184 for(i=0; i<16; i++)
185 self->transformation[i] = object->transformation->matrix[i];
186 }else{
187 /* create one as we requiered it to apply our transformations */
188 object->transformation = g_new0(G3DTransformation, 1);
189 for(i=0; i<16; i++){
190 self->transformation[i] = identity[i];
191 object->transformation->matrix[i] = identity[i];
195 self->is_colliding = false;
197 return self;
200 static void hkl3d_object_free(Hkl3DObject *self)
202 if(!self)
203 return;
205 /* memory leak in libg3d */
206 if(self->g3d && self->g3d->transformation){
207 g_free(self->g3d->transformation);
208 self->g3d->transformation = NULL;
210 if(self->color){
211 delete self->color;
212 self->color = NULL;
214 if(self->btObject){
215 delete self->btObject;
216 self->btObject = NULL;
218 if(self->btShape){
219 delete self->btShape;
220 self->btShape = NULL;
222 if(self->meshes){
223 delete self->meshes;
224 self->meshes = NULL;
226 if(self->axis_name){
227 free(self->axis_name);
228 self->axis_name = NULL;
231 free(self);
234 static void hkl3d_object_set_movable(Hkl3DObject *self, int movable)
236 if(!self)
237 return;
239 if(self->movable != movable){
240 self->movable = movable;
241 delete self->btObject;
242 delete self->btShape;
243 self->btShape = shape_from_trimesh(self->meshes, movable);
244 self->btObject = btObject_from_shape(self->btShape);
248 static void hkl3d_object_set_axis_name(Hkl3DObject *self, const char *name)
250 if(!self || !name || self->axis_name == name)
251 return;
253 if(self->axis_name)
254 free(self->axis_name);
255 self->axis_name = strdup(name);
258 static void matrix_fprintf(FILE *f, const float matrix[])
260 fprintf(f, "transformation : ");
261 for(uint i=0; i<4; ++i){
262 if(i)
263 fprintf(f, " ");
264 for(uint j=0; j<4; ++j){
265 fprintf(f, " %6.3f", matrix[4 * i + j]);
267 fprintf(f, "\n");
271 void hkl3d_object_aabb_get(const Hkl3DObject *self, float from[3], float to[3])
273 btVector3 min, max;
275 self->btShape->getAabb(self->btObject->getWorldTransform(), min, max);
277 from[0] = min.getX();
278 from[1] = min.getY();
279 from[2] = min.getZ();
280 to[0] = max.getX();
281 to[1] = max.getY();
282 to[2] = max.getZ();
285 void hkl3d_object_fprintf(FILE *f, const Hkl3DObject *self)
287 GSList *faces;
288 G3DMaterial* material;
290 faces = self->g3d->faces;
291 material = ((G3DFace *)faces->data)->material;
292 fprintf(f, "id : %d\n", self->id);
293 fprintf(f, "name : %s (%p)\n", self->axis_name, self->axis_name);
294 fprintf(f, "axis : %p\n", self->axis);
295 matrix_fprintf(f, self->transformation);
296 fprintf(f, "btObject : %p\n", self->btObject);
297 fprintf(f, "g3d : %p\n", self->g3d);
298 matrix_fprintf(f, self->g3d->transformation->matrix);
299 fprintf(f, "btShape : %p\n", self->btShape);
300 fprintf(f, "meshes : %p\n", self->meshes);
301 fprintf(f, "color : %f, %f, %f\n", material->r, material->g, material->b);
302 fprintf(f, "is_colliding : %d\n", self->is_colliding);
303 fprintf(f, "hide : %d\n", self->hide);
304 fprintf(f, "added : %d\n", self->added);
305 fprintf(f, "selected : %d\n", self->selected);
308 /**************/
309 /* Hkl3DModel */
310 /**************/
312 static Hkl3DModel *hkl3d_model_new(void)
314 Hkl3DModel *self = NULL;
316 self = HKL3D_MALLOC(Hkl3DModel);
318 self->filename = NULL;
319 self->objects = NULL;
320 self->len = 0;
321 self->g3d = NULL;
323 return self;
326 static void hkl3d_model_free(Hkl3DModel *self)
328 size_t i;
330 if(!self)
331 return;
333 free(self->filename);
334 for(i=0; i<self->len; ++i)
335 hkl3d_object_free(self->objects[i]);
336 free(self->objects);
337 g3d_model_free(self->g3d);
338 free(self);
341 static void hkl3d_model_add_object(Hkl3DModel *self, Hkl3DObject *object)
343 if(!self || !object)
344 return;
346 self->objects = (typeof(self->objects))realloc(self->objects, sizeof(*self->objects) * (self->len + 1));
347 self->objects[self->len++] = object;
350 static void hkl3d_model_delete_object(Hkl3DModel *self, Hkl3DObject *object)
352 size_t i;
354 if(!self || !object)
355 return;
357 if(self != object->model)
358 return;
360 /* find the index of the object */
361 for(i=0; self->objects[i] != object; ++i);
363 hkl3d_object_free(object);
364 self->len--;
365 /* move all above objects of 1 position */
366 if(i < self->len)
367 memmove(object, object + 1, sizeof(object) * (self->len - i));
370 void hkl3d_model_fprintf(FILE *f, const Hkl3DModel *self)
372 fprintf(f, "config (%d):\n", self->len);
373 for(size_t i=0; i<self->len; ++i)
374 hkl3d_object_fprintf(f, self->objects[i]);
378 * Initialize the bullet collision environment.
379 * create the Hkl3DObjects
380 * create the Hkl3DConfig
382 static Hkl3DModel *hkl3d_model_new_from_file(const char *filename)
384 G3DModel *model;
385 Hkl3DModel *self = NULL;
386 GSList *objects; /* lets iterate from the first object. */
387 G3DContext *context;
389 if(!filename)
390 return NULL;
392 /* load the model from the file */
393 context = g3d_context_new();
394 model = g3d_model_load_full(context, filename, 0);
395 g3d_context_free(context);
396 if(!model)
397 return NULL;
398 self = hkl3d_model_new();
400 self->filename = strdup(filename);
401 self->g3d = model;
403 /* create all the attached Hkl3DObjects */
404 objects = model->objects;
405 while(objects){
406 G3DObject *object;
408 object = (G3DObject*)objects->data;
409 if(object->vertex_count){
410 int id;
411 Hkl3DObject *hkl3dObject;
413 id = g_slist_index(model->objects, object);
414 hkl3dObject = hkl3d_object_new(self, object, id);
416 /* remembers objects to avoid memory leak */
417 hkl3d_model_add_object(self, hkl3dObject);
419 objects = g_slist_next(objects);
421 return self;
424 /***************/
425 /* Hkl3DConfig */
426 /***************/
428 static Hkl3DConfig* hkl3d_config_new(void)
430 Hkl3DConfig* self = NULL;
432 self = (Hkl3DConfig*)malloc(sizeof(Hkl3DConfig));
433 if(!self)
434 return NULL;
436 self->models = NULL;
437 self->len = 0;
439 return self;
442 static void hkl3d_config_free(Hkl3DConfig *self)
444 if(!self)
445 return;
447 for(size_t i=0; i<self->len; ++i)
448 hkl3d_model_free(self->models[i]);
449 free(self->models);
450 free(self);
453 static void hkl3d_config_add_model(Hkl3DConfig *self, Hkl3DModel *model)
455 self->models = (typeof(self->models))realloc(self->models, sizeof(*self->models) * (self->len + 1));
456 self->models[self->len++] = model;
459 void hkl3d_config_fprintf(FILE *f, const Hkl3DConfig *self)
461 fprintf(f, "models (%d):\n", self->len);
462 for(size_t i=0; i<self->len; ++i)
463 hkl3d_model_fprintf(f, self->models[i]);
466 /**************/
467 /* Hkl3DStats */
468 /**************/
470 double hkl3d_stats_get_collision_ms(const Hkl3DStats *self)
472 return self->collision.tv_sec*1000. + self->collision.tv_usec/1000.;
475 void hkl3d_stats_fprintf(FILE *f, const Hkl3DStats *self)
477 fprintf(f, "transformation : %f ms collision : %f ms \n",
478 self->transformation.tv_sec*1000. + self->transformation.tv_usec/1000.,
479 hkl3d_stats_get_collision_ms(self));
482 /*************/
483 /* Hkl3DAxis */
484 /*************/
486 static Hkl3DAxis *hkl3d_axis_new(void)
488 Hkl3DAxis *self = NULL;
490 self = HKL3D_MALLOC(Hkl3DAxis);
492 self->objects = NULL; /* do not own the objects */
493 self->len = 0;
495 return self;
498 static void hkl3d_axis_free(Hkl3DAxis *self)
500 if(!self)
501 return;
503 free(self->objects);
504 free(self);
507 /* should be optimized (useless if the Hkl3DObject had a connection with the Hkl3DAxis */
508 static void hkl3d_axis_attach_object(Hkl3DAxis *self, Hkl3DObject *object)
510 object->axis = self;
511 self->objects = (Hkl3DObject **)realloc(self->objects, sizeof(*self->objects) * (self->len + 1));
512 self->objects[self->len++] = object;
515 /* should be optimized (useless if the Hkl3DObject had a connection with the Hkl3DAxis */
516 static void hkl3d_axis_detach_object(Hkl3DAxis *self, Hkl3DObject *object)
518 size_t i;
520 if(!self || !object)
521 return;
523 if(self != object->axis)
524 return;
526 /* find the index of the object in the object list */
527 for(i=0; self->objects[i] != object; ++i);
529 object->axis = NULL;
530 /* move all above objects of 1 position */
531 self->len--;
532 if(i < self->len)
533 memmove(object, object+1, sizeof(object) * (self->len - i));
536 static void hkl3d_axis_fprintf(FILE *f, const Hkl3DAxis *self)
538 if(!f || !self)
539 return;
541 fprintf(f, "Axis len : %d\n", self->len);
542 for(size_t i=0; i<self->len; ++i)
543 hkl3d_object_fprintf(f, self->objects[i]);
546 /*****************/
547 /* Hkl3DGeometry */
548 /*****************/
550 static Hkl3DGeometry *hkl3d_geometry_new(HklGeometry *geometry)
552 uint i;
553 Hkl3DGeometry *self = NULL;
555 self = HKL3D_MALLOC(Hkl3DGeometry);
557 self->geometry = geometry;
558 self->axes = (Hkl3DAxis **)malloc(darray_size(geometry->axes) * sizeof(*self->axes));
560 for(i=0; i<darray_size(geometry->axes); ++i)
561 self->axes[i] = hkl3d_axis_new();
563 return self;
566 static void hkl3d_geometry_free(Hkl3DGeometry *self)
568 uint i;
570 if(!self)
571 return;
573 for(i=0; i<darray_size(self->geometry->axes); ++i)
574 hkl3d_axis_free(self->axes[i]);
575 free(self->axes);
576 free(self);
579 static void hkl3d_geometry_apply_transformations(Hkl3DGeometry *self)
581 HklHolder **holder;
583 darray_foreach(holder, self->geometry->holders){
584 size_t j;
585 btQuaternion btQ(0, 0, 0, 1);
587 size_t len = (*holder)->config->len;
588 for(j=0; j<len; j++){
589 size_t k;
590 size_t idx = (*holder)->config->idx[j];
591 const HklQuaternion *q = hkl_parameter_quaternion_get(darray_item(self->geometry->axes, idx));
592 G3DMatrix G3DM[16];
594 /* conversion beetween hkl -> bullet coordinates */
595 btQ *= btQuaternion(-q->data[1],
596 q->data[3],
597 q->data[2],
598 q->data[0]);
600 /* move each object connected to that hkl Axis. */
601 /* apply the quaternion transformation to the bullet object */
602 /* use the bullet library to compute the OpenGL matrix */
603 /* apply this matrix to the G3DObject for the visualisation */
604 for(k=0; k<self->axes[idx]->len; ++k){
605 self->axes[idx]->objects[k]->btObject->getWorldTransform().setRotation(btQ);
606 self->axes[idx]->objects[k]->btObject->getWorldTransform().getOpenGLMatrix( G3DM );
607 memcpy(self->axes[idx]->objects[k]->g3d->transformation->matrix,
608 &G3DM[0], sizeof(G3DM));
614 static void hkl3d_geometry_fprintf(FILE *f, const Hkl3DGeometry *self)
616 if(!f || !self)
617 return;
619 fprintf(f, "Hkl3DGeometry : \n");
620 hkl_geometry_fprintf(f, self->geometry);
621 for(size_t i=0; i<darray_size(self->geometry->axes); ++i)
622 hkl3d_axis_fprintf(f, self->axes[i]);
625 static Hkl3DAxis *hkl3d_geometry_axis_get(Hkl3DGeometry *self, const char *name)
627 for(size_t i=0; i<darray_size(self->geometry->axes); ++i){
628 if (!strcmp(hkl_parameter_name_get(darray_item(self->geometry->axes, i)),
629 name))
630 return self->axes[i];
632 return NULL;
635 /*********/
636 /* HKL3D */
637 /*********/
639 static void hkl3d_apply_transformations(Hkl3D *self)
641 struct timeval debut, fin;
643 /* set the right transformation of each objects and get numbers */
644 gettimeofday(&debut, NULL);
645 hkl3d_geometry_apply_transformations(self->geometry);
646 gettimeofday(&fin, NULL);
647 timersub(&fin, &debut, &self->stats.transformation);
650 void hkl3d_connect_all_axes(Hkl3D *self)
652 /* connect use the axes names */
653 for(size_t i=0;i<self->config->len;i++)
654 for(size_t j=0;j<self->config->models[i]->len;j++)
655 hkl3d_connect_object_to_axis(self,
656 self->config->models[i]->objects[j],
657 self->config->models[i]->objects[j]->axis_name);
661 * Hkl3D::Hkl3D:
662 * @filename:
663 * @geometry:
667 * Returns:
669 Hkl3D *hkl3d_new(const char *filename, HklGeometry *geometry)
671 Hkl3D *self = NULL;
673 self = HKL3D_MALLOC(Hkl3D);
675 self->geometry = hkl3d_geometry_new(geometry);
676 self->config = hkl3d_config_new();
677 self->model= g3d_model_new();
679 /* initialize the bullet part */
680 self->_btCollisionConfiguration = new btDefaultCollisionConfiguration();
682 #ifdef USE_PARALLEL_DISPATCHER
683 int maxNumOutstandingTasks = 2;
684 PosixThreadSupport::ThreadConstructionInfo constructionInfo("collision",
685 processCollisionTask,
686 createCollisionLocalStoreMemory,
687 maxNumOutstandingTasks);
688 self->_btThreadSupportInterface = new PosixThreadSupport(constructionInfo);
689 self->_btDispatcher = new SpuGatheringCollisionDispatcher(self->_btThreadSupportInterface,
690 maxNumOutstandingTasks,
691 self->_btCollisionConfiguration);
692 #else
693 self->_btDispatcher = new btCollisionDispatcher(self->_btCollisionConfiguration);
694 #endif
695 btGImpactCollisionAlgorithm::registerAlgorithm(self->_btDispatcher);
697 btVector3 worldAabbMin(-1000,-1000,-1000);
698 btVector3 worldAabbMax( 1000, 1000, 1000);
700 self->_btBroadphase = new btAxisSweep3(worldAabbMin, worldAabbMax);
702 self->_btWorld = new btCollisionWorld(self->_btDispatcher,
703 self->_btBroadphase,
704 self->_btCollisionConfiguration);
706 self->filename = filename;
707 if (filename)
708 hkl3d_load_config(self, filename);
710 return self;
713 void hkl3d_free(Hkl3D *self)
715 if(!self)
716 return;
718 /* remove all objects from the collision world */
719 for(size_t i=0; i<self->config->len; ++i)
720 for(size_t j=0; j<self->config->models[i]->len; ++j)
721 if(self->config->models[i]->objects[j]->added)
722 self->_btWorld->removeCollisionObject(self->config->models[i]->objects[j]->btObject);
724 hkl3d_geometry_free(self->geometry);
725 hkl3d_config_free(self->config);
727 if (self->_btWorld)
728 delete self->_btWorld;
729 if (self->_btBroadphase)
730 delete self->_btBroadphase;
731 if (self->_btDispatcher)
732 delete self->_btDispatcher;
733 #ifdef USE_PARALLEL_DISPATCHER
734 if (self->_btThreadSupportInterface){
735 /* delete _btThreadSupportInterface; */
736 /* _btThreadSupportInterface = 0; */
738 #endif
739 if (self->_btCollisionConfiguration)
740 delete self->_btCollisionConfiguration;
741 g_free(self->model); /* do not use g3d_model_free as it is juste a container for all config->model */
743 free(self);
746 Hkl3DModel *hkl3d_add_model_from_file(Hkl3D *self,
747 const char *filename, const char *directory)
749 int current;
750 Hkl3DModel *model = NULL;
751 int res;
753 /* first set the current directory using the directory
754 * parameter. Maybe using openat should be a better solution
755 * in the hkl3d_model_new_from_file */
756 current = open(".", O_RDONLY);
757 if (current < 0)
758 return NULL;
759 res = chdir(directory);
760 if(res < 0)
761 goto close_current;
763 model = hkl3d_model_new_from_file(filename);
764 if(model){
765 /* we can not display two different models with the current g3dviewer code */
766 /* so concatenate this loaded model with the one of hkl3d */
767 self->model->objects = g_slist_concat(self->model->objects, model->g3d->objects);
768 self->model->materials = g_slist_concat(self->model->materials, model->g3d->materials);
770 /* update the Hkl3D internals from the model */
771 hkl3d_config_add_model(self->config, model);
773 /* restore the current directory */
774 res = fchdir(current);
776 return model;
778 close_current:
779 close(current);
780 return NULL;
783 /* check that the axis name is really available in the Geometry */
784 /* if axis name not valid make the object static object->name = NULL */
785 /* ok so check if the axis was already connected or not */
786 /* if already connected check if it was a different axis do the job */
787 /* if not yet connected do the job */
788 /* fill movingCollisionObject and movingG3DObjects vectors for transformations */
789 void hkl3d_connect_object_to_axis(Hkl3D *self, Hkl3DObject *object, const char *name)
791 Hkl3DAxis *axis3d = hkl3d_geometry_axis_get(self->geometry, name);
792 if (!object->movable){
793 if(axis3d){ /* static -> movable */
794 self->_btWorld->removeCollisionObject(object->btObject);
795 hkl3d_object_set_movable(object, true);
796 self->_btWorld->addCollisionObject(object->btObject);
797 object->added = true;
798 hkl3d_axis_attach_object(axis3d, object);
800 }else{
801 if(!axis3d){ /* movable -> static */
802 self->_btWorld->removeCollisionObject(object->btObject);
803 hkl3d_object_set_movable(object, false);
804 self->_btWorld->addCollisionObject(object->btObject);
805 object->added = true;
806 }else{ /* movable -> movable */
807 if(strcmp(object->axis_name, name)){ /* not the same axis */
808 hkl3d_axis_detach_object(object->axis, object);
809 hkl3d_axis_attach_object(axis3d, object);
813 hkl3d_object_set_axis_name(object, name);
816 void hkl3d_load_config(Hkl3D *self, const char *filename)
818 int j = 0;
819 int l;
820 int endEvent = 0;
821 yaml_parser_t parser;
822 yaml_event_t input_event;
823 FILE *file;
824 char *dirc;
825 char *dir;
826 Hkl3DModel *config = NULL;
828 /* Clear the objects. */
829 memset(&parser, 0, sizeof(parser));
830 memset(&input_event, 0, sizeof(input_event));
832 file = fopen(filename, "rb");
833 if (!file){
834 fprintf(stderr, "Could not open the %s config file\n", filename);
835 return;
838 if (!yaml_parser_initialize(&parser))
839 fprintf(stderr, "Could not initialize the parser object\n");
840 yaml_parser_set_input_file(&parser, file);
842 /* compute the dirname of the config file as all model files */
843 /* will be relative to this directory */
844 dirc = strdup(filename);
845 dir = dirname(dirc);
847 while(!endEvent){
848 /* Get the next event. */
849 yaml_parser_parse(&parser, &input_event);
851 /* Check if this is the stream end. */
852 if(input_event.type == YAML_STREAM_END_EVENT)
853 endEvent = 1;
854 if(input_event.type == YAML_DOCUMENT_START_EVENT){
855 j=0;
856 /* skip 4 events */
857 // DOCUMENT-START
858 // SEQUENCE-START
859 // MAPPING-START
860 // SCALAR fileName key
861 for(l=0;l<4;l++){
862 yaml_event_delete(&input_event);
863 yaml_parser_parse(&parser, &input_event);
866 /* the add form file method create a default Hkl3DModel and add it to the HKL3D */
867 /* we just need to update this config with the values from the configuration file */
868 config = hkl3d_add_model_from_file(self, (const char *)input_event.data.scalar.value, dir);
869 /* skip 3 events */
870 // SCALAR objects key
871 // SEQUENCE-START
872 // MAPPING-START
873 for(l=0;l<3;l++){
874 yaml_event_delete(&input_event);
875 yaml_parser_parse(&parser, &input_event);
879 if((input_event.type==YAML_MAPPING_START_EVENT)&& config){
880 j++;
881 /* skip 2 events */
882 // MAPPING-START
883 // SCALAR iD key
884 for(l=0;l<2;l++){
885 yaml_event_delete(&input_event);
886 yaml_parser_parse(&parser, &input_event);
889 /* get the object id */
890 config->objects[j-1]->id = atoi((const char *)input_event.data.scalar.value);
892 /* skip 2 more events */
893 // SCALAR valueId
894 // SCALAR Name key
895 for(l=0;l<2;l++){
896 yaml_event_delete(&input_event);
897 yaml_parser_parse(&parser, &input_event);
900 /* get the name of the object from the config file */
901 hkl3d_object_set_axis_name(config->objects[j-1], (const char *)input_event.data.scalar.value);
902 /* skip 3 events */
903 // SCALAR NameValue
904 // SCALAR transformation key
905 // SEQUENCE-START
906 for(l=0;l<3;l++){
907 yaml_event_delete(&input_event);
908 yaml_parser_parse(&parser, &input_event);
911 /* get the 16 values of the transformation */
912 for(l=0;l<16;l++){
913 config->objects[j-1]->transformation[l] = atof((const char *)input_event.data.scalar.value);
914 yaml_event_delete(&input_event);
915 yaml_parser_parse(&parser, &input_event);
918 /* skip 2 events */
919 // SEQUENCE-END
920 // SCALAR hide key
921 for(l=0;l<2;l++){
922 yaml_event_delete(&input_event);
923 yaml_parser_parse(&parser, &input_event);
926 /* get the hide value */
927 config->objects[j-1]->hide = strcmp((const char *)input_event.data.scalar.value, "no");
928 config->objects[j-1]->g3d->hide = config->objects[j-1]->hide;
930 yaml_event_delete(&input_event);
933 free(dirc);
934 yaml_parser_delete(&parser);
935 fclose(file);
937 /* now that everythings goes fine we can save the filename */
938 self->filename = filename;
940 hkl3d_connect_all_axes(self);
943 void hkl3d_save_config(Hkl3D *self, const char *filename)
945 for(size_t i=0; i<self->config->len; i++){
946 char number[64];
947 int properties1, key1, value1,seq0;
948 int root;
949 time_t now;
950 yaml_emitter_t emitter;
951 yaml_document_t output_document;
952 yaml_event_t output_event;
953 FILE * file;
955 memset(&emitter, 0, sizeof(emitter));
956 memset(&output_document, 0, sizeof(output_document));
957 memset(&output_event, 0, sizeof(output_event));
959 if (!yaml_emitter_initialize(&emitter))
960 fprintf(stderr, "Could not inialize the emitter object\n");
962 /* Set the emitter parameters */
963 file = fopen(filename, "a+");
964 if(!file){
965 fprintf(stderr, "Could not open the config file %s to save\n", filename);
966 return;
968 yaml_emitter_set_output_file(&emitter, file);
969 yaml_emitter_open(&emitter);
971 /* Create an output_document object */
972 if (!yaml_document_initialize(&output_document, NULL, NULL, NULL, 0, 0))
973 fprintf(stderr, "Could not create a output_document object\n");
975 /* Create the root of the config file */
976 time(&now);
977 root = yaml_document_add_sequence(&output_document,
978 (yaml_char_t *)ctime(&now),
979 YAML_BLOCK_SEQUENCE_STYLE);
981 /* create the property of the root sequence */
982 properties1 = yaml_document_add_mapping(&output_document,
983 (yaml_char_t *)YAML_MAP_TAG,
984 YAML_BLOCK_MAPPING_STYLE);
986 yaml_document_append_sequence_item(&output_document, root, properties1);
988 /* add the map key1 : value1 to the property */
989 key1 = yaml_document_add_scalar(&output_document,
990 NULL,
991 (yaml_char_t *)"FileName",
993 YAML_PLAIN_SCALAR_STYLE);
994 value1 = yaml_document_add_scalar(&output_document,
995 NULL,
996 (yaml_char_t *)self->config->models[i]->filename,
998 YAML_PLAIN_SCALAR_STYLE);
999 yaml_document_append_mapping_pair(&output_document, properties1, key1, value1);
1001 /* add the map key1 : seq0 to the first property */
1002 key1 = yaml_document_add_scalar(&output_document,
1003 NULL,
1004 (yaml_char_t *)"Objects",
1006 YAML_PLAIN_SCALAR_STYLE);
1007 /* create the sequence of objects */
1008 seq0 = yaml_document_add_sequence(&output_document,
1009 (yaml_char_t *)YAML_SEQ_TAG,
1010 YAML_BLOCK_SEQUENCE_STYLE);
1011 for(size_t j=0; j<self->config->models[i]->len; j++){
1012 int k;
1013 int properties;
1014 int key;
1015 int value;
1016 int seq1;
1018 properties = yaml_document_add_mapping(&output_document,
1019 (yaml_char_t *)YAML_MAP_TAG,
1020 YAML_BLOCK_MAPPING_STYLE);
1021 yaml_document_append_sequence_item(&output_document,seq0, properties);
1023 key = yaml_document_add_scalar(&output_document,
1024 NULL,
1025 (yaml_char_t *)"Id", -1,
1026 YAML_PLAIN_SCALAR_STYLE);
1028 sprintf(number, "%d", self->config->models[i]->objects[j]->id);
1029 value = yaml_document_add_scalar(&output_document,
1030 NULL,
1031 (yaml_char_t *)number,
1033 YAML_PLAIN_SCALAR_STYLE);
1034 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1036 key = yaml_document_add_scalar(&output_document,
1037 NULL,
1038 (yaml_char_t *)"Name",
1040 YAML_PLAIN_SCALAR_STYLE);
1041 value = yaml_document_add_scalar(&output_document,
1042 NULL,
1043 (yaml_char_t *)self->config->models[i]->objects[j]->axis_name,
1045 YAML_PLAIN_SCALAR_STYLE);
1046 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1048 key = yaml_document_add_scalar(&output_document,
1049 NULL,
1050 (yaml_char_t *)"Transformation",
1052 YAML_PLAIN_SCALAR_STYLE);
1053 seq1 = yaml_document_add_sequence(&output_document,
1054 (yaml_char_t *)YAML_SEQ_TAG,
1055 YAML_FLOW_SEQUENCE_STYLE);
1056 yaml_document_append_mapping_pair(&output_document,properties, key, seq1);
1057 for(k=0; k<16; k++){
1058 sprintf(number, "%f", self->config->models[i]->objects[j]->transformation[k]);
1059 value = yaml_document_add_scalar(&output_document,
1060 NULL,
1061 (yaml_char_t *)number,
1063 YAML_PLAIN_SCALAR_STYLE);
1064 yaml_document_append_sequence_item(&output_document,seq1,value);
1067 key = yaml_document_add_scalar(&output_document,
1068 NULL,
1069 (yaml_char_t *)"Hide",
1071 YAML_PLAIN_SCALAR_STYLE);
1072 if(self->config->models[i]->objects[j]->hide)
1073 value = yaml_document_add_scalar(&output_document,
1074 NULL,
1075 (yaml_char_t *)"yes",
1077 YAML_PLAIN_SCALAR_STYLE);
1078 else
1079 value = yaml_document_add_scalar(&output_document,
1080 NULL,
1081 (yaml_char_t *)"no",
1083 YAML_PLAIN_SCALAR_STYLE);
1084 yaml_document_append_mapping_pair(&output_document,properties,key,value);
1086 yaml_document_append_mapping_pair(&output_document, properties1, key1, seq0);
1088 /* flush the document */
1089 yaml_emitter_dump(&emitter, &output_document);
1090 fclose(file);
1092 yaml_document_delete(&output_document);
1093 yaml_emitter_delete(&emitter);
1098 * Hkl3D::hide_object:
1100 * update the visibility of an Hkl3DObject in the bullet world
1101 * add or remove the object from the _btWorld depending on the hide
1102 * member of the object.
1104 void hkl3d_hide_object(Hkl3D *self, Hkl3DObject *object, int hide)
1106 /* first update the G3DObject */
1107 object->hide = hide;
1108 object->g3d->hide = hide;
1109 if(object->hide){
1110 if (object->added){
1111 self->_btWorld->removeCollisionObject(object->btObject);
1112 object->added = false;
1114 }else{
1115 if(!object->added){
1116 self->_btWorld->addCollisionObject(object->btObject);
1117 object->added = true;
1122 /* remove an object from the model */
1123 void hkl3d_remove_object(Hkl3D *self, Hkl3DObject *object)
1125 if(!self || !object)
1126 return;
1128 hkl3d_hide_object(self, object, TRUE);
1129 hkl3d_axis_detach_object(object->axis, object);
1131 /* now remove the G3DObject from the model */
1132 self->model->objects = g_slist_remove(self->model->objects, object->g3d);
1133 hkl3d_model_delete_object(object->model, object);
1136 /* use for the transparency of colliding objects */
1137 struct ContactSensorCallback : public btCollisionWorld::ContactResultCallback
1139 ContactSensorCallback(Hkl3DObject *object)
1140 : btCollisionWorld::ContactResultCallback(),
1141 collisionObject(object->btObject),
1142 object(object)
1145 btCollisionObject *collisionObject;
1146 Hkl3DObject *object;
1148 virtual btScalar addSingleResult(btManifoldPoint & cp,
1149 const btCollisionObjectWrapper *colObj0, int partId0, int index0,
1150 const btCollisionObjectWrapper *colObj1, int partId1, int index1)
1152 if(colObj0->m_collisionObject == collisionObject
1153 || colObj1->m_collisionObject == collisionObject)
1154 object->is_colliding = TRUE;
1155 return 0;
1159 int hkl3d_is_colliding(Hkl3D *self)
1161 int numManifolds;
1162 struct timeval debut, fin;
1164 /* apply geometry transformation */
1165 hkl3d_apply_transformations(self);
1167 /* perform the collision detection and get numbers */
1168 gettimeofday(&debut, NULL);
1169 if(self->_btWorld){
1170 self->_btWorld->performDiscreteCollisionDetection();
1171 self->_btWorld->updateAabbs();
1173 gettimeofday(&fin, NULL);
1174 timersub(&fin, &debut, &self->stats.collision);
1176 numManifolds = self->_btWorld->getDispatcher()->getNumManifolds();
1178 /* reset all the collisions */
1179 for(size_t i=0; i<self->config->len; i++)
1180 for(size_t j=0; j<self->config->models[i]->len; j++)
1181 self->config->models[i]->objects[j]->is_colliding = FALSE;
1183 /* check all the collisions */
1184 for(size_t i=0; i<self->config->len; i++)
1185 for(size_t j=0; j<self->config->models[i]->len; j++){
1186 Hkl3DObject *object = self->config->models[i]->objects[j];
1187 ContactSensorCallback callback(object);
1188 self->_btWorld->contactTest(object->btObject, callback);
1191 return numManifolds != 0;
1195 * Hkl3D::get_bounding_boxes:
1196 * @min:
1197 * @max:
1199 * get the bounding boxes of the current world from the bullet internals.
1201 void hkl3d_get_bounding_boxes(Hkl3D *self,
1202 struct btVector3 *min, struct btVector3 *max)
1204 self->_btWorld->getBroadphase()->getBroadphaseAabb(*min, *max);
1207 int hkl3d_get_nb_manifolds(Hkl3D *self)
1209 return self->_btDispatcher->getNumManifolds();
1212 int hkl3d_get_nb_contacts(Hkl3D *self, int manifold)
1214 return self->_btDispatcher->getManifoldByIndexInternal(manifold)->getNumContacts();
1217 void hkl3d_get_collision_coordinates(Hkl3D *self, int manifold, int contact,
1218 double *xa, double *ya, double *za,
1219 double *xb, double *yb, double *zb)
1221 btPersistentManifold *contactManifold;
1223 contactManifold = self->_btDispatcher->getManifoldByIndexInternal(manifold);
1224 btManifoldPoint & pt = contactManifold->getContactPoint(contact);
1225 btVector3 ptA = pt.getPositionWorldOnA();
1226 btVector3 ptB = pt.getPositionWorldOnB();
1228 *xa = ptA.x();
1229 *ya = ptA.y();
1230 *za = ptA.z();
1231 *xb = ptB.x();
1232 *yb = ptB.y();
1233 *zb = ptB.z();
1236 void hkl3d_fprintf(FILE *f, const Hkl3D *self)
1239 fprintf(f, "filename : %s\n", self->filename);
1240 hkl3d_geometry_fprintf(f, self->geometry);
1241 fprintf(f, "\n");
1242 fprintf(f, "model : %p\n", self->model);
1243 hkl3d_stats_fprintf(f, &self->stats);
1244 hkl3d_config_fprintf(f, self->config);
1246 fprintf(f, "_btCollisionConfiguration : %p\n", self->_btCollisionConfiguration);
1247 fprintf(f, "_btBroadphase : %p\n", self->_btBroadphase);
1248 fprintf(f, "_btWorld : %p\n", self->_btWorld);
1249 fprintf(f, "_btDispatcher : %p\n", self->_btDispatcher);
1250 #ifdef USE_PARALLEL_DISPATCHER
1251 fprintf(f, "_btThreadSupportInterface : %p\n", self->_btThreadSupportInterface);
1252 #endif