Code

glib/gtestutils.h is not available on gutsy, so switching to include of
[inkscape.git] / src / helper / units.cpp
1 #define __SP_PAPER_C__
3 /*
4  * SPUnit
5  *
6  * Ported from libgnomeprint
7  *
8  * Authors:
9  *   Dirk Luetjens <dirk@luedi.oche.de>
10  *   Yves Arrouye <Yves.Arrouye@marin.fdn.fr>
11  *   Lauris Kaplinski <lauris@ximian.com>
12  *   bulia byak <buliabyak@users.sf.net>
13  *
14  * Copyright 1999-2001 Ximian, Inc. and authors
15  *
16  */
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include "helper/units.h"
23 #include <glib.h> // g_assert()
24 #include <glibmm/i18n.h>
25 #include "unit-constants.h"
26 #include "svg/svg-length.h"
28 /* todo: use some fancy unit program */
30 /* The order determines the order of the list returned by sp_unit_get_list.
31  * (It can also affect string lookups if there are any duplicates in the
32  * current locale... hopefully none.)  If you re-order this list, then you must
33  * also re-order the SPUnitId enum values accordingly.  Run `make check' (which
34  * calls sp_unit_table_sane) to ensure that the two are in sync.
35  */
36 SPUnit const sp_units[] = {
37     {SP_UNIT_SCALE, SP_UNIT_DIMENSIONLESS, 1.0, NONE, SVGLength::NONE, N_("Unit"), "", N_("Units"), ""},
38     {SP_UNIT_PT, SP_UNIT_ABSOLUTE, PX_PER_PT, SP_PT, SVGLength::PT, N_("Point"), N_("pt"), N_("Points"), N_("Pt")},
39     {SP_UNIT_PX, SP_UNIT_DEVICE, PX_PER_PX, SP_PX, SVGLength::PX, N_("Pixel"), N_("px"), N_("Pixels"), N_("Px")}, 
40     /* You can add new elements from this point forward */
41     {SP_UNIT_PERCENT, SP_UNIT_DIMENSIONLESS, 0.01, NONE, SVGLength::PERCENT, N_("Percent"), N_("%"), N_("Percents"), N_("%")},
42     {SP_UNIT_MM, SP_UNIT_ABSOLUTE, PX_PER_MM, SP_MM, SVGLength::MM, N_("Millimeter"), N_("mm"), N_("Millimeters"), N_("mm")},
43     {SP_UNIT_CM, SP_UNIT_ABSOLUTE, PX_PER_CM, SP_CM, SVGLength::CM, N_("Centimeter"), N_("cm"), N_("Centimeters"), N_("cm")},
44     {SP_UNIT_M, SP_UNIT_ABSOLUTE, PX_PER_M, SP_M, SVGLength::NONE, N_("Meter"), N_("m"), N_("Meters"), N_("m")}, // no svg_unit
45     {SP_UNIT_IN, SP_UNIT_ABSOLUTE, PX_PER_IN, SP_IN, SVGLength::INCH, N_("Inch"), N_("in"), N_("Inches"), N_("in")},
46     /* Volatiles do not have default, so there are none here */
47     // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
48     {SP_UNIT_EM, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EM, N_("Em square"), N_("em"), N_("Em squares"), N_("em")},
49     // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
50     {SP_UNIT_EX, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EX, N_("Ex square"), N_("ex"), N_("Ex squares"), N_("ex")},
51 };
53 #define sp_num_units G_N_ELEMENTS(sp_units)
55 SPUnit const *
56 sp_unit_get_by_abbreviation(gchar const *abbreviation)
57 {
58     g_return_val_if_fail(abbreviation != NULL, NULL);
60     for (unsigned i = 0 ; i < sp_num_units ; i++) {
61         if (!g_strcasecmp(abbreviation, sp_units[i].abbr)) return &sp_units[i];
62         if (!g_strcasecmp(abbreviation, sp_units[i].abbr_plural)) return &sp_units[i];
63     }
65     return NULL;
66 }
68 gchar const *
69 sp_unit_get_abbreviation(SPUnit const *unit)
70 {
71     g_return_val_if_fail(unit != NULL, NULL);
73     return unit->abbr;
74 }
76 gchar const *
77 sp_unit_get_plural (SPUnit const *unit)
78 {
79     g_return_val_if_fail(unit != NULL, NULL);
81     return unit->plural;
82 }
84 SPMetric
85 sp_unit_get_metric(SPUnit const *unit)
86 {
87     g_return_val_if_fail(unit != NULL, NONE);
89     return unit->metric;
90 }
92 guint 
93 sp_unit_get_svg_unit(SPUnit const *unit)
94 {
95     g_return_val_if_fail(unit != NULL, NONE);
97     return unit->svg_unit;
98 }
100 GSList *
101 sp_unit_get_list(guint bases)
103     g_return_val_if_fail((bases & ~SP_UNITS_ALL) == 0, NULL);
105     GSList *units = NULL;
106     for (unsigned i = sp_num_units ; i--; ) {
107         if (bases & sp_units[i].base) {
108             units = g_slist_prepend(units, (gpointer) &sp_units[i]);
109         }
110     }
112     return units;
115 void
116 sp_unit_free_list(GSList *units)
118     g_slist_free(units);
121 /* These are pure utility */
122 /* Return TRUE if conversion is possible */
123 gboolean
124 sp_convert_distance(gdouble *distance, SPUnit const *from, SPUnit const *to)
126     g_return_val_if_fail(distance != NULL, FALSE);
127     g_return_val_if_fail(from != NULL, FALSE);
128     g_return_val_if_fail(to != NULL, FALSE);
130     if (from == to) return TRUE;
131     if ((from->base == SP_UNIT_DIMENSIONLESS) || (to->base == SP_UNIT_DIMENSIONLESS)) {
132         *distance = *distance * from->unittobase / to->unittobase;
133         return TRUE;
134     }
135     if ((from->base == SP_UNIT_VOLATILE) || (to->base == SP_UNIT_VOLATILE)) return FALSE;
137     if ((from->base == to->base)
138         || (from->base == SP_UNIT_DEVICE) && (to->base == SP_UNIT_ABSOLUTE)
139         || (from->base == SP_UNIT_ABSOLUTE) && (to->base == SP_UNIT_DEVICE))
140     {
141         *distance = *distance * from->unittobase / to->unittobase;
142         return TRUE;
143     }
145     return FALSE;
148 /** @param devicetransform for device units. */
149 /* TODO: Remove the ctmscale parameter given that we no longer have SP_UNIT_USERSPACE. */
150 gdouble
151 sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to)
153     if (&from == &to) {
154         return from_dist;
155     }
156     if (from.base == to.base) {
157         gdouble ret = from_dist;
158         bool const succ = sp_convert_distance(&ret, &from, &to);
159         g_assert(succ);
160         return ret;
161     }
162     if ((from.base == SP_UNIT_DIMENSIONLESS)
163         || (to.base == SP_UNIT_DIMENSIONLESS))
164     {
165         return from_dist * from.unittobase / to.unittobase;
166     }
167     g_return_val_if_fail(((from.base != SP_UNIT_VOLATILE)
168                           && (to.base != SP_UNIT_VOLATILE)),
169                          from_dist);
171     gdouble absolute;
172     switch (from.base) {
173         case SP_UNIT_ABSOLUTE:
174         case SP_UNIT_DEVICE:
175             absolute = from_dist * from.unittobase;
176             break;
177         default:
178             g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, from.base);
179             return from_dist;
180     }
182     gdouble ret;
183     switch (to.base) {
184         default:
185             g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, to.base);
186             /* FALL-THROUGH */
187         case SP_UNIT_ABSOLUTE:
188         case SP_UNIT_DEVICE:
189             ret = absolute / to.unittobase;
190             break;
191     }
193     return ret;
196 /* Some more convenience */
198 gdouble
199 sp_units_get_pixels(gdouble const units, SPUnit const &unit)
201     if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
202         return units * unit.unittobase;
203     } else {
204         g_warning("Different unit bases: No exact unit conversion available");
205         return units * unit.unittobase;
206     }
209 gdouble
210 sp_pixels_get_units(gdouble const pixels, SPUnit const &unit)
212     if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
213         return pixels / unit.unittobase;
214     } else {
215         g_warning("Different unit bases: No exact unit conversion available");
216         return pixels / unit.unittobase;
217     }
220 bool
221 sp_units_table_sane()
223     for (unsigned i = 0; i < G_N_ELEMENTS(sp_units); ++i) {
224         if (unsigned(sp_units[i].unit_id) != i) {
225             return false;
226         }
227     }
228     return true;
231 /** Converts angle (in deg) to compass display */
232 double 
233 angle_to_compass(double angle)
235     double ret = 90 - angle;
236     if (ret < 0)
237         ret = 360 + ret;
238     return ret;
241 /** Converts angle (in deg) to compass display */
242 double 
243 angle_from_compass(double angle)
245     double ret = 90 - angle;
246     if (ret > 180)
247         ret = ret - 180;
248     return ret;
252 /*
253   Local Variables:
254   mode:c++
255   c-file-style:"stroustrup"
256   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
257   indent-tabs-mode:nil
258   fill-column:99
259   End:
260 */
261 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :