~cypheon/elfelli

2f78c6ce2d7e9d3659b1f1c5af4802a6d3cd7336 — Johann Rudloff 14 years ago 2cc2a48
Added class XmlLoader which can load scenes from an Elfelli XML file.
M src/Application.cpp => src/Application.cpp +17 -1
@@ 19,6 19,7 @@

#include "Application.h"
#include "Simulation.h"
#include "XmlLoader.h"

using namespace Gtk;



@@ 106,6 107,21 @@ void Application::on_export_png_activate()
  save_dlg.hide();
}

void Application::on_open_activate()
{
  XmlLoader loader;

  Simulation *tmp_sim = new Simulation;

  if(loader.load("test.xml", tmp_sim) == 0)
  {
    sim_canvas = *tmp_sim;
    sim_canvas.refresh();
  }

  delete tmp_sim;
}

void Application::on_quit_activate()
{
  quit();


@@ 196,7 212,7 @@ bool Application::setup_ui_actions()

  action_group->add( Action::create("MenuScene", _("_Scene")) );
  action_group->add( Action::create("New", Stock::NEW) , sigc::mem_fun(*this, &Application::reset_simulation));
  action_group->add( Action::create("Open", Stock::OPEN) );
  action_group->add( Action::create("Open", Stock::OPEN) , sigc::mem_fun(*this, &Application::on_open_activate));
  action_group->add( Action::create("SaveAs", Stock::SAVE_AS) );
  action_group->add( Action::create("ExportPNG", _("Export _PNG")) , sigc::mem_fun(*this, &Application::on_export_png_activate));
  action_group->add( Action::create("ExportSVG", _("Export S_VG")) );

M src/Application.h => src/Application.h +1 -0
@@ 60,6 60,7 @@ class Application
  void on_about_activate();
  void on_quit_activate();
  void on_export_png_activate();
  void on_open_activate();

  Gtk::Main gtk_main;
  Gtk::Window main_win;

M src/SConscript => src/SConscript +1 -0
@@ 6,6 6,7 @@ elfelli_sources = ['Application.cpp',
                   'Canvas.cpp',
                   'Simulation.cpp',
                   'SimulationCanvas.cpp',
                   'XmlLoader.cpp',
                   'Main.cpp']

elfelli = env.Program('elfelli', elfelli_sources)

M src/Simulation.h => src/Simulation.h +4 -1
@@ 100,11 100,14 @@ class Simulation
{
public:
  Vec2 force_at(const Vec2& pos, float charge);
  void reset(){bodies.clear();result.clear();};
  void reset(){bodies.clear();plates.clear();result.clear();};

  void add_body(const Vec2& v, float charge);
  void add_plate(const Vec2& a, const Vec2& b, float charge);

  const std::vector<Body> get_bodies() const{return bodies;};
  const std::vector<PlateBody> get_plates() const{return plates;};

  Body& operator[](int n){return bodies[n];};
  int n_bodies(){return bodies.size();};


M src/SimulationCanvas.cpp => src/SimulationCanvas.cpp +11 -0
@@ 46,6 46,17 @@ SimulationCanvas::~SimulationCanvas()
{
}

void SimulationCanvas::operator=(const Simulation& sim)
{
  bodies = sim.get_bodies();
  plates = sim.get_plates();

  drag_state = DRAG_STATE_NONE;
  mouse_pressed = false;
  mouse_over = -1;
  active = -1;
}

void SimulationCanvas::refresh()
{
  run();

M src/SimulationCanvas.h => src/SimulationCanvas.h +2 -0
@@ 52,6 52,8 @@ public:
  SimulationCanvas();
  ~SimulationCanvas();

  void operator=(const Simulation& sim);

  void refresh();
  void clear();
  bool delete_body(int n);

A src/XmlLoader.cpp => src/XmlLoader.cpp +221 -0
@@ 0,0 1,221 @@
/*
 * XmlLoader.cpp
 * Copyright (C) 2006  Johann Rudloff
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <string>
#include <cstring>
#include <sstream>
#include <iostream>

#include "XmlLoader.h"

class TypeException{};
inline float str_to_float(const std::string& str)
{
  std::istringstream stream;
  float r;
  stream.str(str);
  stream >> r;

  if(stream.fail())
    throw TypeException();

  return r;
}

namespace Elfelli
{

  const char *XmlLoader::version_string = "elfelli-xml-1";

XmlLoader::XmlLoader()
{
  parser = XML_ParserCreate(NULL);
}

XmlLoader::~XmlLoader()
{
  XML_ParserFree(parser);
}

int XmlLoader::load(const char *filename, Simulation *target)
{
  const int MAX_FILE_SIZE = 100*1024;

  XML_ParserReset(parser, NULL);
  XML_SetUserData(parser, this);
  sim = target;

  sim->reset();

  errors = 0;
  scene_started = false;

  void *buf = XML_GetBuffer(parser, MAX_FILE_SIZE);
  std::ifstream in(filename);
  if(!in)
    return 1;

  in.read(reinterpret_cast<char *>(buf), MAX_FILE_SIZE);

  XML_SetStartElementHandler(parser, XmlLoader::start_element);
  XML_ParseBuffer(parser, std::strlen(reinterpret_cast<char *>(buf)), 1);

  return errors;
}

void XmlLoader::start_element(void *data, const XML_Char *name, const XML_Char **attrs)
{
  XmlLoader *xml = static_cast<XmlLoader *>(data);
  
  if(xml->scene_started)
  {
    if(strcmp(name, "point") == 0)
    {
      bool have_x, have_y, have_charge;
      float x, y, charge;

      have_x=have_y=have_charge=false;

      for(int i=0; attrs[i]; i+=2)
      {
        const XML_Char *attr = attrs[i];

        try
        {
          if(!have_x && strcmp(attr, "x") == 0)
          {
            x = str_to_float(attrs[i+1]);
            have_x = true;
          }
          else if(!have_y && strcmp(attr, "y") == 0)
          {
            y = str_to_float(attrs[i+1]);
            have_y = true;
          }
          else if(!have_charge && strcmp(attr, "charge") == 0)
          {
            charge = str_to_float(attrs[i+1]);
            have_charge = true;
          }
          else
          {
            std::cerr << "warning: unexpected attribute: `" << attr << "'.\n";
          }
        }
        catch(TypeException)
        {
          std::cerr << "warning: no float value: " << attrs[i+1] << "\n";
        }
      }

      if(have_x && have_y && have_charge)
      {
        xml->sim->add_body(Vec2(x, y), charge);
        std::cerr << "added body\n";
      }
    }
    else if(strcmp(name, "plate") == 0)
    {
      bool have_x1, have_y1, have_x2, have_y2, have_charge;
      float x1, y1, x2, y2, charge;

      have_x1=have_y1=have_x2=have_y2=have_charge=false;

      for(int i=0; attrs[i]; i+=2)
      {
        const XML_Char *attr = attrs[i];

        try
        {
          if(!have_x1 && strcmp(attr, "x1") == 0)
          {
            x1 = str_to_float(attrs[i+1]);
            have_x1 = true;
          }
          else if(!have_y1 && strcmp(attr, "y1") == 0)
          {
            y1 = str_to_float(attrs[i+1]);
            have_y1 = true;
          }
          else if(!have_x2 && strcmp(attr, "x2") == 0)
          {
            x2 = str_to_float(attrs[i+1]);
            have_x2 = true;
          }
          else if(!have_y2 && strcmp(attr, "y2") == 0)
          {
            y2 = str_to_float(attrs[i+1]);
            have_y2 = true;
          }
          else if(!have_charge && strcmp(attr, "charge") == 0)
          {
            charge = str_to_float(attrs[i+1]);
            have_charge = true;
          }
          else
          {
            std::cerr << "warning: unexpected attribute: `" << attr << "'.\n";
          }
        }
        catch(TypeException)
        {
          std::cerr << "warning: no float value: " << attrs[i+1] << "\n";
        }
      }

      if(have_x1 && have_y1 && have_x2 && have_y2 && have_charge)
      {
        xml->sim->add_plate(Vec2(x1, y1), Vec2(x2, y2), charge);
        std::cerr << "added plate\n";
      }
    }
    else
    {
      std::cerr << "error: wrong element `" << name << "' expected `point' or `plate'.\n";
      xml->errors++;
    }
  }
  else
  {
    if(strcmp(name, "scene") == 0)
    {
      bool right_version = false;
      for(int i=0; attrs[i]; i+=2)
      {
        if(strcmp(attrs[i], "version") == 0)
        {
          if(strcmp(attrs[i+1], version_string) == 0)
          {
            right_version=true;
          }
        }
      }
      if(right_version)
      {
        xml->scene_started = true;
      }
      else
      {
        xml->errors++;
      }
    }
  }
}

}

A src/XmlLoader.h => src/XmlLoader.h +55 -0
@@ 0,0 1,55 @@
// -*- C++ -*-
/*
 * XmlLoader.h
 * Copyright (C) 2006  Johann Rudloff
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _XML_LOADER_H_
#define _XML_LOADER_H_

#include <fstream>
#include <expat.h>

#include "Simulation.h"

namespace Elfelli
{

class XmlLoader
{
public:
  XmlLoader();
  ~XmlLoader();

  int load(const char *filename, Simulation *target);

  static const char* version_string;

private:
  static void start_element(void *data, const XML_Char *name, const XML_Char **attrs);

  XML_Parser parser;
  Simulation *sim;

  int errors;
  bool scene_started;

};

}

#endif // _XML_LOADER_H_