[gcalctool] Add a unit-manager object to track units
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcalctool] Add a unit-manager object to track units
- Date: Thu, 27 Jan 2011 01:11:10 +0000 (UTC)
commit 80a1044429dc53684f7c60f4cb57f2a091915486
Author: Robert Ancell <robert ancell canonical com>
Date: Wed Jan 26 17:58:59 2011 +1000
Add a unit-manager object to track units
src/Makefile.am | 8 +-
src/gcalctool.c | 8 ++
src/math-converter.c | 4 +-
src/math-equation.c | 9 ++
src/math-equation.h | 3 +
src/mp-equation.c | 7 +-
src/unit-manager.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/unit-manager.h | 36 ++++++
src/units.c | 182 ------------------------------
src/units.h | 8 --
10 files changed, 363 insertions(+), 200 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e0c6ce3..e512538 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -47,8 +47,8 @@ gcalctool_SOURCES = \
mp-serializer.h \
financial.c \
financial.h \
- units.c \
- units.h \
+ unit-manager.c \
+ unit-manager.h \
unittest.c \
unittest.h
@@ -68,8 +68,8 @@ gcalccmd_SOURCES = \
mp-serializer.h\
math-enums.c \
math-enums.h \
- units.c \
- units.h
+ unit-manager.c \
+ unit-manager.h
gcalccmd_LDADD = \
$(GCALCCMD_LIBS) \
diff --git a/src/gcalctool.c b/src/gcalctool.c
index b2bb23b..38fffb3 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -39,6 +39,13 @@ version(const gchar *progname)
}
+static int
+do_convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data)
+{
+ return unit_manager_convert(unit_manager_get_default(), x, x_units, z_units, z);
+}
+
+
static void
solve(const char *equation)
{
@@ -51,6 +58,7 @@ solve(const char *equation)
options.base = 10;
options.wordlen = 32;
options.angle_units = MP_DEGREES;
+ options.convert = do_convert;
error = mp_equation_parse(equation, &options, &result, NULL);
if(error == PARSER_ERR_MP) {
diff --git a/src/math-converter.c b/src/math-converter.c
index 219c69c..feb2f73 100644
--- a/src/math-converter.c
+++ b/src/math-converter.c
@@ -20,7 +20,7 @@
#include "math-converter.h"
#include "mp-serializer.h"
-#include "units.h"
+#include "unit-manager.h"
#include "currency.h"
enum {
@@ -194,7 +194,7 @@ update_result_label(MathConverter *converter)
target_units = math_equation_get_target_units(converter->priv->equation);
if (!source_units || !target_units)
enabled = FALSE;
- else if (!units_convert(&x, source_units, target_units, &z)) {
+ else if (!unit_manager_convert(math_equation_get_unit_manager(converter->priv->equation), &x, source_units, target_units, &z)) {
if (!currency_convert(&x, source_units, target_units, &z))
enabled = FALSE;
}
diff --git a/src/math-equation.c b/src/math-equation.c
index 252d4c7..1df9a47 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -99,6 +99,7 @@ struct MathEquationPrivate
gboolean in_solve;
MathVariables *variables;
+ UnitManager *unit_manager;
MpSerializer *serializer;
GAsyncQueue *queue;
@@ -127,6 +128,13 @@ math_equation_get_variables(MathEquation *equation)
}
+UnitManager *
+math_equation_get_unit_manager(MathEquation *equation)
+{
+ return equation->priv->unit_manager;
+}
+
+
static void
get_ans_offsets(MathEquation *equation, gint *start, gint *end)
{
@@ -1844,6 +1852,7 @@ math_equation_init(MathEquation *equation)
g_strfreev(digits);
equation->priv->variables = math_variables_new();
+ equation->priv->unit_manager = unit_manager_get_default();
equation->priv->state.status = g_strdup("");
equation->priv->word_size = 32;
diff --git a/src/math-equation.h b/src/math-equation.h
index 5ee13c3..819b157 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -24,6 +24,7 @@
#include <gtk/gtk.h>
#include "mp.h"
#include "math-variables.h"
+#include "unit-manager.h"
#include "mp-serializer.h"
G_BEGIN_DECLS
@@ -56,6 +57,8 @@ MathEquation *math_equation_new(void);
MathVariables *math_equation_get_variables(MathEquation *equation);
+UnitManager *math_equation_get_unit_manager(MathEquation *equation);
+
gunichar math_equation_get_digit_text(MathEquation *equation, guint digit);
void math_equation_set_status(MathEquation *equation, const gchar *status);
diff --git a/src/mp-equation.c b/src/mp-equation.c
index 9e136ca..505609f 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -22,7 +22,6 @@
#include "mp-equation-private.h"
#include "mp-equation-parser.h"
#include "mp-equation-lexer.h"
-#include "units.h"
extern int _mp_equation_parse(yyscan_t yyscanner);
@@ -249,10 +248,10 @@ get_function(MPEquationParserState *state, const char *name, const MPNumber *x,
static int
convert(MPEquationParserState *state, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
{
- if (!units_convert(x, x_units, z_units, z))
+ if (state->options->convert)
+ return state->options->convert(x, x_units, z_units, z, state->options->callback_data);
+ else
return 0;
-
- return 1;
}
diff --git a/src/unit-manager.c b/src/unit-manager.c
new file mode 100644
index 0000000..5fb5fe4
--- /dev/null
+++ b/src/unit-manager.c
@@ -0,0 +1,298 @@
+#include <string.h>
+
+#include "unit-manager.h"
+
+typedef struct
+{
+ gchar *name;
+ MPNumber value;
+} Unit;
+
+typedef struct
+{
+ gchar *name;
+ GList *units;
+} UnitCategory;
+
+struct UnitManagerPrivate
+{
+ GList *categories;
+};
+
+G_DEFINE_TYPE (UnitManager, unit_manager, G_TYPE_OBJECT);
+
+
+static UnitManager *default_unit_manager = NULL;
+
+
+UnitManager *
+unit_manager_new()
+{
+ return g_object_new(unit_manager_get_type(), NULL);
+}
+
+
+static void
+add_category(UnitManager *manager, const gchar *name, const gchar *units[][2])
+{
+ int i;
+
+ for (i = 0; units[i][0]; i++) {
+ MPNumber r;
+ mp_set_from_string(units[i][1], 10, &r);
+ unit_manager_add(manager, name, units[i][0], &r);
+ }
+}
+
+
+UnitManager *
+unit_manager_get_default()
+{
+ const char *angle_units[][2] = {
+ /* FIXME: Approximations of 1/(units in a circle)
+ * Therefore, 360 deg != 400 grads */
+ {"grad", "0.0025"},
+ {"gradian", "0.0025"},
+ {"gradians", "0.0025"},
+ {"deg", "0.002777778"},
+ {"degree", "0.002777778"},
+ {"degrees", "0.002777778"},
+ {"rad", "0.159154943"},
+ {"radian", "0.159154943"},
+ {"radians", "0.159154943"},
+ {NULL, NULL}
+ };
+
+ const char *length_units[][2] = {
+ {"parsec", "30857000000000000"},
+ {"parsecs", "30857000000000000"},
+ {"pc", "30857000000000000"},
+ {"lightyear", "9460730472580800"},
+ {"lightyears", "9460730472580800"},
+ {"ly", "9460730472580800"},
+ {"au", "149597870691"},
+ {"nm", "1852000"},
+ {"mile", "1609.344"},
+ {"miles", "1609.344"},
+ {"mi", "1609.344"},
+ {"kilometer", "1000"},
+ {"kilometers", "1000"},
+ {"km", "1000"},
+ {"kms", "1000"},
+ {"cable", "219.456"},
+ {"cables", "219.456"},
+ {"cb", "219.456"},
+ {"fathom", "1.8288"},
+ {"fathoms", "1.8288"},
+ {"ftm", "1.8288"},
+ {"meter", "1"},
+ {"meters", "1"},
+ {"m", "1"},
+ {"yard", "0.9144"},
+ {"yards", "0.9144"},
+ {"yd", "0.9144"},
+ {"foot", "0.3048"},
+ {"feet", "0.3048"},
+ {"ft", "0.3048"},
+ {"inch", "0.0254"},
+ {"inches", "0.0254"},
+ {"centimeter", "0.01"},
+ {"centimeters", "0.01"},
+ {"cm", "0.01"},
+ {"cms", "0.01"},
+ {"millimeter", "0.001"},
+ {"millimeters", "0.001"},
+ {"mm", "0.001"},
+ {"micrometer", "0.000001"},
+ {"micrometers", "0.000001"},
+ {"um", "0.000001"},
+ {"nanometer", "0.000000001"},
+ {"nanometers", "0.000000001"},
+ {NULL, NULL}
+ };
+
+ const char *area_units[][2] = {
+ {"hectare", "10000"},
+ {"hectares", "10000"},
+ {"acre", "4046.8564224"},
+ {"acres", "4046.8564224"},
+ {"m²", "1"},
+ {"cm²", "0.001"},
+ {"mm²", "0.000001"},
+ {NULL, NULL}
+ };
+
+ const char *volume_units[][2] = {
+ {"m³", "1000"},
+ {"gallon", "3.785412"},
+ {"gallons", "3.785412"},
+ {"gal", "3.785412"},
+ {"litre", "1"},
+ {"litres", "1"},
+ {"liter", "1"},
+ {"liters", "1"},
+ {"L", "1"},
+ {"quart", "0.9463529"},
+ {"quarts", "0.9463529"},
+ {"qt", "0.9463529"},
+ {"pint", "0.4731765"},
+ {"pints", "0.4731765"},
+ {"pt", "0.4731765"},
+ {"millilitre", "0.001"},
+ {"millilitres", "0.001"},
+ {"milliliter", "0.001"},
+ {"milliliters", "0.001"},
+ {"mL", "0.001"},
+ {"cm³", "0.001"},
+ {"mm³", "0.000001"},
+ {NULL, NULL}
+ };
+
+ const char *weight_units[][2] = {
+ {"tonne", "1000"},
+ {"tonnes", "1000"},
+ {"kilograms", "1"},
+ {"kilogramme", "1"},
+ {"kilogrammes", "1"},
+ {"kg", "1"},
+ {"kgs", "1"},
+ {"pound", "0.45359237"},
+ {"pounds", "0.45359237"},
+ {"lb", "0.45359237"},
+ {"ounce", "0.02834952"},
+ {"ounces", "0.02834952"},
+ {"oz", "0.02834952"},
+ {"gram", "0.001"},
+ {"grams", "0.001"},
+ {"gramme", "0.001"},
+ {"grammes", "0.001"},
+ {"g", "0.001"},
+ {NULL, NULL}
+ };
+
+ const char *time_units[][2] = {
+ {"year", "31557600"},
+ {"years", "31557600"},
+ {"day", "86400"},
+ {"days", "86400"},
+ {"hour", "3600"},
+ {"hours", "3600"},
+ {"minute", "60"},
+ {"minutes", "60"},
+ {"second", "1"},
+ {"seconds", "1"},
+ {"s", "1"},
+ {"millisecond", "0.001"},
+ {"milliseconds", "0.001"},
+ {"ms", "0.001"},
+ {"microsecond", "0.000001"},
+ {"microseconds", "0.000001"},
+ {"us", "0.000001"},
+ {NULL, NULL}
+ };
+
+ if (default_unit_manager)
+ return default_unit_manager;
+
+ default_unit_manager = unit_manager_new();
+ add_category(default_unit_manager, "angles", angle_units);
+ add_category(default_unit_manager, "length", length_units);
+ add_category(default_unit_manager, "area", area_units);
+ add_category(default_unit_manager, "volume", volume_units);
+ add_category(default_unit_manager, "weight", weight_units);
+ add_category(default_unit_manager, "time", time_units);
+
+ return default_unit_manager;
+}
+
+
+static UnitCategory *
+category_new(const gchar *name)
+{
+ UnitCategory *category;
+ category = g_malloc0(sizeof(UnitCategory));
+ category->name = g_strdup(name);
+ return category;
+}
+
+
+static UnitCategory *
+get_category(UnitManager *manager, const gchar *category)
+{
+ GList *iter;
+
+ for (iter = manager->priv->categories; iter; iter = iter->next) {
+ UnitCategory *c = iter->data;
+ if (strcmp(c->name, category) == 0)
+ return c;
+ }
+
+ return NULL;
+}
+
+
+void
+unit_manager_add(UnitManager *manager, const gchar *category, const gchar *name, MPNumber *value)
+{
+ UnitCategory *c;
+ Unit *unit;
+
+ c = get_category(manager, category);
+ if (!c) {
+ c = category_new(category);
+ manager->priv->categories = g_list_append(manager->priv->categories, c);
+ }
+
+ unit = g_malloc0(sizeof(Unit));
+ unit->name = g_strdup(name);
+ mp_set_from_mp(value, &unit->value);
+ c->units = g_list_append(c->units, unit);
+}
+
+
+static Unit *
+get_unit(UnitCategory *category, const gchar *name)
+{
+ GList *iter;
+
+ for (iter = category->units; iter; iter = iter->next) {
+ Unit *unit = iter->data;
+ if (strcmp(unit->name, name) == 0)
+ return unit;
+ }
+
+ return NULL;
+}
+
+
+gboolean
+unit_manager_convert(UnitManager *manager, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
+{
+ GList *iter;
+
+ for (iter = manager->priv->categories; iter; iter = iter->next) {
+ UnitCategory *c = iter->data;
+ Unit *unit_x, *unit_z;
+ if ((unit_x = get_unit(c, x_units)) && (unit_z = get_unit(c, z_units))) {
+ mp_multiply(x, &unit_x->value, z);
+ mp_divide(z, &unit_z->value, z);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+static void
+unit_manager_class_init(UnitManagerClass *klass)
+{
+ g_type_class_add_private(klass, sizeof(UnitManagerPrivate));
+}
+
+
+static void
+unit_manager_init(UnitManager *manager)
+{
+ manager->priv = G_TYPE_INSTANCE_GET_PRIVATE(manager, unit_manager_get_type(), UnitManagerPrivate);
+}
diff --git a/src/unit-manager.h b/src/unit-manager.h
new file mode 100644
index 0000000..d68bfda
--- /dev/null
+++ b/src/unit-manager.h
@@ -0,0 +1,36 @@
+#ifndef UNIT_MANAGER_H
+#define UNIT_MANAGER_H
+
+#include <glib-object.h>
+#include "mp.h"
+
+G_BEGIN_DECLS
+
+#define UNIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), unit_manager_get_type(), UnitManager))
+
+typedef struct UnitManagerPrivate UnitManagerPrivate;
+
+typedef struct
+{
+ GObject parent_instance;
+ UnitManagerPrivate *priv;
+} UnitManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} UnitManagerClass;
+
+GType unit_manager_get_type(void);
+
+UnitManager *unit_manager_new();
+
+UnitManager *unit_manager_get_default();
+
+void unit_manager_add(UnitManager *manager, const gchar *category, const gchar *name, MPNumber *value);
+
+gboolean unit_manager_convert(UnitManager *manager, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z);
+
+G_END_DECLS
+
+#endif /* UNIT_MANAGER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]