Logo Search packages:      
Sourcecode: v-sim version File versions  Download package

plane.c

/*   EXTRAITS DE LA LICENCE
      Copyright CEA, contributeurs : Luc BILLARD et Damien
      CALISTE, laboratoire L_Sim, (2001-2005)
  
      Adresse mèl :
      BILLARD, non joignable par mèl ;
      CALISTE, damien P caliste AT cea P fr.

      Ce logiciel est un programme informatique servant à visualiser des
      structures atomiques dans un rendu pseudo-3D. 

      Ce logiciel est régi par la licence CeCILL soumise au droit français et
      respectant les principes de diffusion des logiciels libres. Vous pouvez
      utiliser, modifier et/ou redistribuer ce programme sous les conditions
      de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
      sur le site "http://www.cecill.info".

      Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
      pris connaissance de la licence CeCILL, et que vous en avez accepté les
      termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
      Copyright CEA, contributors : Luc BILLARD et Damien
      CALISTE, laboratoire L_Sim, (2001-2005)

      E-mail address:
      BILLARD, not reachable any more ;
      CALISTE, damien P caliste AT cea P fr.

      This software is a computer program whose purpose is to visualize atomic
      configurations in 3D.

      This software is governed by the CeCILL  license under French law and
      abiding by the rules of distribution of free software.  You can  use, 
      modify and/ or redistribute the software under the terms of the CeCILL
      license as circulated by CEA, CNRS and INRIA at the following URL
      "http://www.cecill.info". 

      The fact that you are presently reading this means that you have had
      knowledge of the CeCILL license and that you accept its terms. You can
      find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#include "plane.h"

#include <stdlib.h>
#include <math.h>

#include <opengl.h>
#include <visu_object.h>

Plane_hidingMode plane_hidingMode = plane_hideUnion;

struct Plane_struct
{
  /* Internal object gestion. */
  GObject parent;
  gboolean dispose_has_run;

  /* Normal vector, unitary. */
  float nVect[3];
  /* Normal vector, user given. */
  float nVectUser[3];

  /* Distance between origin and intersection of the plane
     and the line made by origin and normal vector. */
  float dist;

  /* Color of that plane. */
  Color *color;

  /* Internal variables */
  /* Intersections with the bounding box.
     Consist of a GList of float[3], can be NULL if
     there is no interstection. */
  GList *inter;
  /* Isobarycenter G of all intersection points, required to order
     these points to form a convex polygon. */
  float pointG[3];
  /* The plane can hide the nodes on one of its side.
     This variable can be PLANE_SIDE_PLUS or PLANE_SIDE_MINUS or
     PLANE_SIDE_NONE. It codes the side of the plane which hides the nodes.
     If PLANE_SIDE_NONE is selected all nodes are rendered. */
  int hiddenSide;
  /* Store if the plane is rendered or not.
     Default is TRUE. */
  gboolean rendered;
};

enum
  {
    PLANE_MOVED_SIGNAL,
    PLANE_NB_SIGNAL
  };

struct PlaneClass_struct
{
  GObjectClass parent;
};

/* Internal variables. */
static GObjectClass *parent_class = NULL;
static guint plane_signals[PLANE_NB_SIGNAL] = { 0 };

/* Object gestion methods. */
static void plane_class_init(PlaneClass *klass);
static void plane_init      (Plane *obj);
static void plane_dispose   (GObject* obj);
static void plane_finalize  (GObject* obj);

/* Local methods. */
static int comparePolygonPoint(gconstpointer pointA, gconstpointer pointB, gpointer data);

GType plane_get_type(void)
{
  static GType plane_type = 0;

  if (!plane_type)
    {
      static const GTypeInfo plane_info =
      {
        sizeof (PlaneClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc)plane_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof (Plane),
        0,
        (GInstanceInitFunc)plane_init,
      NULL
      };
      plane_type = g_type_register_static(G_TYPE_OBJECT, "PlaneType",
                                     &plane_info, 0);
      DBG_fprintf(stderr, "Plane : creating the type Plane %d.\n",
              (int)plane_type);
    }

  return plane_type;
}

static void plane_class_init(PlaneClass *klass)
{
  DBG_fprintf(stderr, "Plane : creating the class of the object.\n");
  parent_class = g_type_class_peek_parent(klass);

  DBG_fprintf(stderr, "                - adding new signals ;\n");
  plane_signals[PLANE_MOVED_SIGNAL] =
    g_signal_newv("moved", G_TYPE_FROM_CLASS(klass),
              G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
              NULL, NULL, NULL, g_cclosure_marshal_VOID__VOID,
              G_TYPE_NONE, 0, NULL);

  /* Connect freeing methods. */
  G_OBJECT_CLASS(klass)->dispose  = plane_dispose;
  G_OBJECT_CLASS(klass)->finalize = plane_finalize;
}

static void plane_init(Plane *obj)
{
  obj->dispose_has_run = FALSE;

  DBG_fprintf(stderr, "Plane : creating a new plane (%p).\n", (gpointer)obj);
  obj->inter = (GList*)0;
  obj->hiddenSide = PLANE_SIDE_NONE;
  obj->nVectUser[0] = 0.;
  obj->nVectUser[1] = 0.;
  obj->nVectUser[2] = 0.;
  obj->dist = 0.;
  obj->color = (Color*)0;
  obj->rendered = TRUE;
}

/* This method can be called several times.
   It should unref all of its reference to
   GObjects. */
static void plane_dispose(GObject* obj)
{
  DBG_fprintf(stderr, "Plane : dispose object %p.\n", (gpointer)obj);

  if (PLANE(obj)->dispose_has_run)
    return;

  PLANE(obj)->dispose_has_run = TRUE;
  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->dispose(obj);
}
/* This method is called once only. */
static void plane_finalize(GObject* obj)
{
  GList *tmpLst;

  g_return_if_fail(obj);

  DBG_fprintf(stderr, "Plane : finalize object %p.\n", (gpointer)obj);

  /* Deleting the intersection nodes if any. */
  tmpLst = PLANE(obj)->inter;
  while (tmpLst)
    {
      free(tmpLst->data);
      tmpLst = g_list_next(tmpLst);
    }

  /* Chain up to the parent class */
  G_OBJECT_CLASS(parent_class)->finalize(obj);
}

Plane* planeNew_undefined()
{
  Plane *plane;

  /* Create the object with defaulty values. */
  plane = PLANE(g_object_new(PLANE_TYPE, NULL));
  g_return_val_if_fail(plane, (Plane*)0);
  return plane;
}

Plane* planeNew(OpenGLView *view, float vect[3], float dist, Color *color)
{
  Plane *plane;
  int res;

  g_return_val_if_fail(view && color, (Plane*)0);

  /* Create the object with defaulty values. */
  plane = PLANE(g_object_new(PLANE_TYPE, NULL));
  g_return_val_if_fail(plane, (Plane*)0);

  res = (planeSet_normalVector(plane, vect) < 0);
  res = (planeSet_distanceFromOrigin(plane, dist) < 0) || res;
  res = (planeSet_color(plane, color) < 0) || res;
  res = planeComputeInter(plane, view) || res;
  
  if (res)
    {
      g_object_unref(G_OBJECT(plane));
      return (Plane*)0;
    }

  return plane;
}

int planeSet_normalVector(Plane *plane, float vect[3])
{
  int i;
  float norm;

  g_return_val_if_fail(IS_PLANE_TYPE(plane), -1);

  if (vect[0] == plane->nVectUser[0] &&
      vect[1] == plane->nVectUser[1] &&
      vect[2] == plane->nVectUser[2])
    return 0;
  if (vect[0] * vect[0] + vect[1] * vect[1] + vect[2] * vect[2] == 0.)
    {
      fprintf(stderr, "WARNING! '%s' has been called with a null value for parameter '%s'.\n",
            "planeSet_normalVector", "vect");
      return -1;
    }

  norm = 0.;
  for (i = 0; i < 3; i++)
    {
      norm += vect[i] * vect[i];
      plane->nVect[i] = vect[i];
      plane->nVectUser[i] = vect[i];
    }
  norm = sqrt(norm);
  for (i = 0; i < 3; i++)
    plane->nVect[i] /= norm;

  DBG_fprintf(stderr, "Visu Plane : set normal vector (%f,%f,%f) for plane %p.\n",
            plane->nVect[0], plane->nVect[1], plane->nVect[2], (gpointer)plane);
  g_signal_emit(G_OBJECT(plane), plane_signals[PLANE_MOVED_SIGNAL], 0, NULL);
  return 1;
}

int planeSet_distanceFromOrigin(Plane *plane, float dist)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), -1);

  if (plane->dist == dist)
    return 0;

  plane->dist = dist;
  DBG_fprintf(stderr, "Visu Plane : set distance from origin %f for plane %p.\n",
            dist, (gpointer)plane);
  g_signal_emit(G_OBJECT(plane), plane_signals[PLANE_MOVED_SIGNAL], 0, NULL);
  return 1;
}

int planeSet_color(Plane *plane, Color *color)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), -1);

  if (color == plane->color)
    return 0;

  plane->color = color;
  return 1;
}
int planeSet_rendered(Plane *plane, gboolean rendered)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), -1);

  if (rendered == plane->rendered)
    return 0;

  plane->rendered = rendered;
  return 1;
}
gboolean planeGet_rendered(Plane *plane)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), FALSE);

  return plane->rendered;
}

void planeGet_barycentre(Plane *plane, float *point)
{
  g_return_if_fail(IS_PLANE_TYPE(plane) && point);

  point[0] = plane->pointG[0];
  point[1] = plane->pointG[1];
  point[2] = plane->pointG[2];
}
GList* planeGet_intersection(Plane *plane)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), (GList*)0);

  return plane->inter;
}

int planeComputeInter(Plane* plane, OpenGLView *view)
{
  float lambda, denom;
  float l[12][3], a[12][3];
  int i, j, n;
  float *inter;
  GList *tmpLst;

  g_return_val_if_fail(IS_PLANE_TYPE(plane) && view, 1);

  /* RAZ old intersection list. */
  if (plane->inter)
    {
      tmpLst = plane->inter;
      while(tmpLst)
      {
        free((float*)tmpLst->data);
        tmpLst = g_list_next(tmpLst);
      }
      g_list_free(plane->inter);
      plane->inter = (GList*)0;
    }
  /* Compute, vector and position for the box. */
  for (i = 0; i < 3; i++)
    {
      l[0][i] = view->box->p2[i] - view->box->p1[i];
      l[1][i] = view->box->p3[i] - view->box->p2[i];
      l[2][i] = view->box->p4[i] - view->box->p3[i];
      l[3][i] = view->box->p1[i] - view->box->p4[i];
      l[4][i] = view->box->p5[i] - view->box->p1[i];
      l[5][i] = view->box->p6[i] - view->box->p2[i];
      l[6][i] = view->box->p7[i] - view->box->p3[i];
      l[7][i] = view->box->p8[i] - view->box->p4[i];
      l[8][i] = view->box->p6[i] - view->box->p5[i];
      l[9][i] = view->box->p7[i] - view->box->p6[i];
      l[10][i] = view->box->p8[i] - view->box->p7[i];
      l[11][i] = view->box->p5[i] - view->box->p8[i];
      a[0][i] = view->box->p1[i];
      a[1][i] = view->box->p2[i];
      a[2][i] = view->box->p3[i];
      a[3][i] = view->box->p4[i];
      a[4][i] = view->box->p1[i];
      a[5][i] = view->box->p2[i];
      a[6][i] = view->box->p3[i];
      a[7][i] = view->box->p4[i];
      a[8][i] = view->box->p5[i];
      a[9][i] = view->box->p6[i];
      a[10][i] = view->box->p7[i];
      a[11][i] = view->box->p8[i];
    }
  n = 0;
  for (i = 0; i < 3; i++)
    plane->pointG[i] = 0.;
  /*
    The plane is defined by n1x+n2y+n3z-d=0 with (n1,n2,n3) the normal vector (unitary)
    and d the algebric distance from the origin.
    A segment {P} of the box is defined by P=A+lambda.l with A a vertex, l a vector
    in the direction of the segment and lambda a real.
    If it exists a lambda that can solve P(lambda) in the plane equation, and this lambda
    is in [0;1] then this is the intersection.
   */
  for (i = 0; i < 12; i++)
    {
      denom = 0.;
      for (j = 0; j < 3; j++)
      denom += plane->nVect[j] * l[i][j];
      if (denom != 0.)
      {
        lambda = plane->dist;
        for (j = 0; j < 3; j++)
          lambda -= plane->nVect[j] * a[i][j];
        lambda /= denom;
        if (lambda >= 0. && lambda <= 1.)
          {
            inter = malloc(sizeof(float) * 3);
            if (!inter)
            {
              allocationProblems();
              exit(1);
            }
            for (j = 0; j < 3; j++)
            {
              inter[j] = a[i][j] + lambda * l[i][j];
              plane->pointG[j] += inter[j];
            }
            n += 1;
            plane->inter = g_list_append(plane->inter, (gpointer)inter);
            DBG_fprintf(stderr, "Visu Plane : a new intersection (%f,%f,%f) for plane %p.\n",
                    inter[0], inter[1], inter[2], (gpointer)plane);
          }
      }
    }
  if (n > 0)
    {
      for (i = 0; i < 3; i++)
      plane->pointG[i] /= (float)n;
      plane->inter = g_list_sort_with_data(plane->inter, comparePolygonPoint, (gpointer)plane);
    }

  return 0;
}
int planesComputeInter_list(OpenGLView *view, GList *list)
{
  int res;
  GList *tmpLst;

  g_return_val_if_fail(view, 1);
  
  res = 0;
  tmpLst = list;
  while(tmpLst)
    {
      res = planeComputeInter((Plane*)tmpLst->data, view) || res;
      tmpLst = g_list_next(tmpLst);
    }
  return res;
}

void planeDraw(Plane* plane, OpenGLView *view)
{
  GList *tmpLst;
  float mat[5] = {1., 0.0, 1.0, 0.0, 0.0};

  g_return_if_fail(view && IS_PLANE_TYPE(plane));

  tmpLst = plane->inter;
  if (tmpLst && plane->rendered)
    {
      glDisable(GL_CULL_FACE);
      setOpenGlMaterial(mat, plane->color->rgba);
      glPushMatrix();
      glTranslated(-view->box->dxxs2, -view->box->dyys2, -view->box->dzzs2);
      glBegin(GL_POLYGON);
      while (tmpLst)
      {
        glVertex3f(((float*)tmpLst->data)[0],
                 ((float*)tmpLst->data)[1],
                 ((float*)tmpLst->data)[2]);
        tmpLst = g_list_next(tmpLst);
      }
      glEnd();
      glPopMatrix();  
      glEnable(GL_CULL_FACE);
      glCullFace(GL_BACK);
    }
}
void planesDraw_list(OpenGLView *view, GList *list)
{
  GList *tmpLst;

  g_return_if_fail(view);

  DBG_fprintf(stderr, "Plane : drawing list of planes.\n");
  tmpLst = list;
  while(tmpLst)
    {
      DBG_fprintf(stderr, " | plane %p\n", tmpLst->data);
      planeDraw((Plane*)tmpLst->data, view);
      tmpLst = g_list_next(tmpLst);
    }
}

static int comparePolygonPoint(gconstpointer pointA, gconstpointer pointB, gpointer data)
{
  Plane *plane;
  float vectGA[3], vectGB[3];
  int i;
  float det;

  plane = (Plane*)data;
  for (i = 0; i < 3; i++)
    {
      vectGA[i] = ((float*)pointA)[i] - plane->pointG[i];
      vectGB[i] = ((float*)pointB)[i] - plane->pointG[i];
    }
  det = vectGA[0] * vectGB[1] * plane->nVect[2] + vectGB[0] * plane->nVect[1] * vectGA[2] +
    plane->nVect[0] * vectGA[1] * vectGB[2] - vectGA[2] * vectGB[1] * plane->nVect[0] -
    vectGA[1] * vectGB[0] * plane->nVect[2] - vectGA[0] * vectGB[2] * plane->nVect[1];
  if (det < 0.)
    return -1;
  else if (det > 0.)
    return 1;
  else
    return 0;
}

void planeGet_nVectUser(Plane *plane, float *vect)
{
  int i;

  g_return_if_fail(IS_PLANE_TYPE(plane));

  for (i = 0; i < 3; i++)
    vect[i] = plane->nVectUser[i];
}

void planeGet_color(Plane *plane, Color **color)
{
  g_return_if_fail(IS_PLANE_TYPE(plane));

  *color = plane->color;
}

void planeGet_distanceFromOrigin(Plane *plane, float *dist)
{
  g_return_if_fail(IS_PLANE_TYPE(plane));

  *dist = plane->dist;
}

int planeSet_hiddenState(Plane *plane, int side)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), 0);
  g_return_val_if_fail(side == PLANE_SIDE_NONE ||
                   side == PLANE_SIDE_PLUS ||
                   side == PLANE_SIDE_MINUS, 0);

  DBG_fprintf(stderr, "Visu Plane : hide state (%d, old %d) for plane %p.\n",
            side, plane->hiddenSide, (gpointer)plane);
  if (plane->hiddenSide == side)
    return 0;
  plane->hiddenSide = side;
  return 1;
}
int planeGet_hiddenState(Plane *plane)
{
  g_return_val_if_fail(IS_PLANE_TYPE(plane), 0);
  return plane->hiddenSide;
}
int planeShowHide_all(VisuData *visuData, GList *listOfPlanes)
{
  int i, j, k;
  int reDraw;
  float point[3];
  float pScal;
  gboolean hidingMode, visibility;
  GList *tmpLst;

  DBG_fprintf(stderr, "Planes : applying masking properties of planes.\n");

  /* Remove planes of the given list that doesn't have a masking action. */
  tmpLst = listOfPlanes;
  listOfPlanes = (GList*)0;
  while(tmpLst)
    {
      if (((Plane*)tmpLst->data)->hiddenSide != PLANE_SIDE_NONE)
      listOfPlanes = g_list_append(listOfPlanes, tmpLst->data);
      else
      DBG_fprintf(stderr, " | plane %p has a masking property.\n", tmpLst->data);
      tmpLst = g_list_next(tmpLst);
    }

  hidingMode = TRUE;
  switch (plane_hidingMode)
    {
    case plane_hideUnion: hidingMode = TRUE; break;
    case plane_hideInter: hidingMode = FALSE; break;
    default: break;
    }

  reDraw = 0;
  /* We change the rendered attribute of all nodes, very expensive... */
  if (listOfPlanes)
    for (i = 0; i < visuData->ntype; i++)
      for(j = 0; j < visuData->numberOfStoredNodes[i]; j++)
      {
        visuDataGet_nodePosition(visuData, &visuData->nodes[i][j], point);
      
        visibility = hidingMode;
        tmpLst = listOfPlanes;
        while(tmpLst)
          {
            pScal = 0.;
            for (k = 0; k < 3; k++)
            pScal += ((Plane*)tmpLst->data)->nVect[k] *
              (point[k] - ((Plane*)tmpLst->data)->pointG[k]);
            switch (plane_hidingMode)
            {
            case plane_hideUnion:
              visibility =
                visibility && (pScal * ((Plane*)tmpLst->data)->hiddenSide > 0.);
              break;
            case plane_hideInter:
              visibility =
                visibility || (pScal * ((Plane*)tmpLst->data)->hiddenSide > 0.);
              break;
            default: break;
            }
            tmpLst = g_list_next(tmpLst);
          }
        if (!visibility)
          reDraw = visuNodeSet_visibility(&visuData->nodes[i][j], visibility) || reDraw;
      }
  if (reDraw)
    return 1;
  else
    return 0;
}
int planeSet_hidingMode(Plane_hidingMode mode)
{
  g_return_val_if_fail(mode < plane_nbHidingMode, 0);

  if (mode == plane_hidingMode)
    return 0;

  plane_hidingMode = mode;
  return 1;
}

/***************************************************
 * Parsing of data files containing list of planes *
 ***************************************************/
/* Know elements. */
#define PLANES_PARSER_ELEMENT_PLANES    "planes"
#define PLANES_PARSER_ELEMENT_PLANE     "plane"
#define PLANES_PARSER_ELEMENT_GEOMETRY  "geometry"
#define PLANES_PARSER_ELEMENT_HIDE      "hide"
#define PLANES_PARSER_ELEMENT_COLOR     "color"
/* Known attributes. */
#define PLANES_PARSER_ATTRIBUTES_RENDERED "rendered"
#define PLANES_PARSER_ATTRIBUTES_VECTOR   "normal-vector"
#define PLANES_PARSER_ATTRIBUTES_DISTANCE "distance"
#define PLANES_PARSER_ATTRIBUTES_STATUS   "status"
#define PLANES_PARSER_ATTRIBUTES_INVERT   "invert"
#define PLANES_PARSER_ATTRIBUTES_RGBA     "rgba"

/* This method is called for every element that is parsed.
   The user_data must be a GList of planes. When a 'plane'
   element, a new plane is created and prepend in the list.
   When 'geometry' or other qualificative elements are
   found, the first plane of the list is modified accordingly. */
void listOfPlanes_element(GMarkupParseContext *context,
                          const gchar         *element_name,
                          const gchar        **attribute_names,
                          const gchar        **attribute_values,
                          gpointer             user_data,
                          GError             **error)
{
  GList **planesList;
  Plane *plane;
  float normalVector[3];
  float distance;
  float colorRGBA[4];
  Color *color;
  int i, res;
  int side, set;
  gboolean rendered;

  g_return_if_fail(user_data);
  planesList = (GList **)user_data;

  DBG_fprintf(stderr, "Planes parser : found '%s' element.\n", element_name);
  if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANES))
    {
      /* Should have no attributes. */
      if (attribute_names[0])
      {
        g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                  _("Unexpected attribute '%s' for element '%s'."),
                  attribute_names[0], PLANES_PARSER_ELEMENT_PLANES);
        return;
      }
      /* Initialise planeList. */
      if (*planesList)
      g_warning("Unexpected non null pointer as user_data for the "
              "plane parser.");
      *planesList = (GList*)0;
    }
  else
    {
      if (!strcmp(element_name, PLANES_PARSER_ELEMENT_PLANE))
      {
        rendered = TRUE;
        /* May have one attribute. */
        if (attribute_names[0])
          {
            if (!strcmp(attribute_names[0], PLANES_PARSER_ATTRIBUTES_RENDERED) )
            {
              if (!strcmp(attribute_values[0], "yes"))
                rendered = TRUE;
              else if (!strcmp(attribute_values[0], "no"))
                rendered = FALSE;
              else
                g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                        _("Invalid value '%s' for attribute '%s'."),
                        attribute_values[0], PLANES_PARSER_ATTRIBUTES_RENDERED);
            }
            else
            {
              g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                        _("Unexpected attribute '%s' for element '%s'."),
                        attribute_names[0], PLANES_PARSER_ELEMENT_PLANE);
              return;
            }
          }
        plane = planeNew_undefined();
        planeSet_rendered(plane, rendered);
        DBG_fprintf(stderr, "Planes parser : adding plane %p to list %p.\n",
                  (gpointer)plane, (gpointer)(*planesList));
        *planesList = g_list_prepend(*planesList, (gpointer)plane);
        DBG_fprintf(stderr, " | new plane list : %p.\n", (gpointer)(*planesList));
      }
      else
      {
        if (!*planesList || !(*planesList)->data)
          {
            g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                    _("DTD error : parent element '%s' of element '%s' is missing."),
                    PLANES_PARSER_ELEMENT_PLANE, element_name);
            return;
          }
        if (!strcmp(element_name, PLANES_PARSER_ELEMENT_GEOMETRY))
          {
            DBG_fprintf(stderr, "Planes parser : associated plane : %p.\n", (*planesList)->data);
            for(i = 0; attribute_names[i]; i++)
            {
              if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_VECTOR))
                {
                  res = sscanf(attribute_values[i], "%g %g %g",
                           normalVector, normalVector + 1, normalVector + 2);
                  if (res != 3)
                  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                            _("Invalid value '%s' for attribute '%s'."),
                            attribute_values[i], PLANES_PARSER_ATTRIBUTES_VECTOR);
                  planeSet_normalVector((Plane*)(*planesList)->data, normalVector);
                }
              else if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_DISTANCE))
                {
                  res = sscanf(attribute_values[i], "%g", &distance);
                  if (res != 1)
                  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                            _("Invalid value '%s' for attribute '%s'."),
                            attribute_values[i], PLANES_PARSER_ATTRIBUTES_DISTANCE);
                  planeSet_distanceFromOrigin((Plane*)(*planesList)->data, distance);
                }
              else
                g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                        _("Unexpected attribute '%s' for element '%s'."),
                        attribute_names[i], PLANES_PARSER_ELEMENT_GEOMETRY);
            }
          }
        else if (!strcmp(element_name, PLANES_PARSER_ELEMENT_HIDE))
          {
            set = 0;
            side = 1;
            for(i = 0; attribute_names[i]; i++)
            {
              if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_STATUS))
                {
                  if (!strcmp(attribute_values[i], "yes"))
                  set = 1;
                  else if (!strcmp(attribute_values[i], "no"))
                  set = 0;
                  else
                  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                            _("Invalid value '%s' for attribute '%s'."),
                            attribute_values[i], PLANES_PARSER_ATTRIBUTES_STATUS);
                }
              else if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_INVERT))
                {
                  if (!strcmp(attribute_values[i], "yes"))
                  side = -1;
                  else if (!strcmp(attribute_values[i], "no"))
                  side = 1;
                  else
                  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                            _("Invalid value '%s' for attribute '%s'."),
                            attribute_values[i], PLANES_PARSER_ATTRIBUTES_INVERT);
                }
              else
                g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                        _("Unexpected attribute '%s' for element '%s'."),
                        attribute_names[i], PLANES_PARSER_ELEMENT_HIDE);
            }
            ((Plane*)(*planesList)->data)->hiddenSide = side * set;
          }
        else if (!strcmp(element_name, "color"))
          {
            for(i = 0; attribute_names[i]; i++)
            {
              if (!strcmp(attribute_names[i], PLANES_PARSER_ATTRIBUTES_RGBA))
                {
                  res = sscanf(attribute_values[i], "%g %g %g %g",
                           colorRGBA, colorRGBA + 1, colorRGBA + 2, colorRGBA + 3);
                  if (res != 4)
                  g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
                            _("Invalid value '%s' for attribute '%s'."),
                            attribute_values[i], PLANES_PARSER_ATTRIBUTES_RGBA);
                  color = colorAdd_floatRGBA(colorRGBA, &res);
                  planeSet_color(((Plane*)(*planesList)->data), color);
                }
              else
                g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                        _("Unexpected attribute '%s' for element '%s'."),
                        attribute_names[i], PLANES_PARSER_ELEMENT_COLOR);
            }
          }
        else
          g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
                  _("Unexpected element '%s'."), element_name);
      }
    }
}

/* Check when a element is closed that everything required has been set. */
void listOfPlanes_end(GMarkupParseContext *context,
                  const gchar         *element_name,
                  gpointer             user_data,
                  GError             **error)
{
  GList **planesList;
  float *vect;

  g_return_if_fail(user_data);
  planesList = (GList**)user_data;
  
  g_return_if_fail(*planesList && (*planesList)->data);

  if (!strcmp(element_name, "plane"))
    {
      if (!((Plane*)(*planesList)->data)->color)
      {
        g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                  _("DTD error : missing or wrong child element '%s'."),
                  PLANES_PARSER_ELEMENT_COLOR);
        return;
      }
      vect = ((Plane*)(*planesList)->data)->nVectUser;
      if (vect[0] == 0. && vect[1] == 0. && vect[2] == 0.)
      {
        g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE,
                  _("DTD error : missing or wrong child element '%s'."),
                  PLANES_PARSER_ELEMENT_GEOMETRY);
        return;
      }
    }
  
}

/* What to do when an error is raised. */
void listOfPlanes_error(GMarkupParseContext *context,
                          GError              *error,
                          gpointer             user_data)
{
  DBG_fprintf(stderr, "Planes parser : error raised '%s'.\n", error->message);
}

gboolean planesParse_XMLFile(gchar* filename, GList **list, GError **error)
{
  GMarkupParseContext* xmlContext;
  GMarkupParser parser;
  gboolean res;
  GIOChannel *xmlData;
  gsize size;
  gchar *buffer;
  GIOStatus ioRes;

  g_return_val_if_fail(filename && list, FALSE);

  xmlData = g_io_channel_new_file(filename, "r", error);
  if (!xmlData)
    return FALSE;

  buffer = (gchar*)0;
  ioRes = g_io_channel_read_to_end(xmlData, &buffer, &size, error);
  if (ioRes != G_IO_STATUS_NORMAL)
    {
      g_io_channel_unref(xmlData);
      return FALSE;
    }

  ioRes = g_io_channel_shutdown(xmlData, FALSE, error);
  if (ioRes != G_IO_STATUS_NORMAL)
    {
      g_io_channel_unref(xmlData);
      return FALSE;
    }
  
  g_io_channel_unref(xmlData);

  /* Create context. */
  *list = (GList*)0;
  parser.start_element = listOfPlanes_element;
  parser.end_element   = listOfPlanes_end;
  parser.text          = NULL;
  parser.passthrough   = NULL;
  parser.error         = listOfPlanes_error;
  xmlContext = g_markup_parse_context_new(&parser, 0, list, NULL);

  /* Parse data. */
  res = g_markup_parse_context_parse(xmlContext, buffer, size, error);

  /* Free buffers. */
  g_markup_parse_context_free(xmlContext);
  g_free(buffer);

  /* Need to reverse the list since elements have been prepended. */
  *list = g_list_reverse(*list);

  return res;
}
gboolean planesExport_XMLFile(gchar* filename, GList *list, GError **error)
{
  GIOChannel *xmlData;
  GIOStatus ioRes;
  GString *buffer;
  Plane *plane;
  gsize sizeWritten;

  g_return_val_if_fail(filename && list, FALSE);

  xmlData = g_io_channel_new_file(filename, "w", error);
  if (!xmlData)
    return FALSE;

  buffer = g_string_new("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
  g_string_append(buffer, "<planes>\n");
  while (list)
    {
      plane = (Plane*)list->data;
      if (plane->rendered)
      g_string_append(buffer, "  <plane rendered=\"yes\">\n");
      else
      g_string_append(buffer, "  <plane rendered=\"no\">\n");
      g_string_append_printf(buffer, "    <geometry normal-vector=\"%g %g %g\""
                       " distance=\"%g\" />\n", plane->nVectUser[0],
                       plane->nVectUser[1], plane->nVectUser[2],
                       plane->dist);
      switch (plane->hiddenSide)
      {
      case PLANE_SIDE_NONE:
        g_string_append(buffer, "    <hide status=\"no\" invert=\"no\" />\n");
        break;
      case PLANE_SIDE_MINUS:
        g_string_append(buffer, "    <hide status=\"yes\" invert=\"yes\" />\n");
        break;
      case PLANE_SIDE_PLUS:
        g_string_append(buffer, "    <hide status=\"yes\" invert=\"no\" />\n");
        break;
      default:
        g_warning("Unknown hiddenSide attribute ofr the given plane.");
      };
      g_string_append_printf(buffer, "    <color rgba=\"%g %g %g %g\" />\n",
                       plane->color->rgba[0], plane->color->rgba[1],
                       plane->color->rgba[2], plane->color->rgba[3]);
      g_string_append(buffer, "  </plane>\n");
      list = g_list_next(list);
    }
  g_string_append(buffer, "</planes>\n");

  /* Write buffer to the file. */
  ioRes = g_io_channel_write_chars(xmlData, buffer->str, buffer->len,
                           &sizeWritten, error);
  if (ioRes != G_IO_STATUS_NORMAL)
    {
      g_string_free(buffer, TRUE);
      g_io_channel_unref(xmlData);
      return FALSE;
    }
  
  /* Close the file. */
  ioRes = g_io_channel_shutdown(xmlData, TRUE, error);
  if (ioRes != G_IO_STATUS_NORMAL)
    {
      g_string_free(buffer, TRUE);
      g_io_channel_unref(xmlData);
      return FALSE;
    }
  
  /* Free buffers. */
  g_io_channel_unref(xmlData);
  g_string_free(buffer, TRUE);

  return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index