Use #defined constants for converting between different units.
[synfig.git] / synfig-core / trunk / src / synfig / distance.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file distance.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include "distance.h"
33 #include "renddesc.h"
34 #include "general.h"
35 #include <ctype.h>
36 #endif
37
38 /* === U S I N G =========================================================== */
39
40 using namespace std;
41 using namespace etl;
42 using namespace synfig;
43
44 /* === M A C R O S ========================================================= */
45
46 #define POINTS_PER_INCH           (72.0)
47 #define INCHES_PER_METER          (39.3700787402)
48 #define POINTS_PER_METER          (POINTS_PER_INCH*INCHES_PER_METER)
49 #define CENTIMETERS_PER_METER (100.0)
50 #define MILLIMETERS_PER_METER (1000.0)
51
52 #define METERS_PER_UNIT           (rend_desc.get_physical_w()/abs(rend_desc.get_tl()[0]-rend_desc.get_br()[0]))
53
54 /* === G L O B A L S ======================================================= */
55
56 /* === P R O C E D U R E S ================================================= */
57
58 /* === M E T H O D S ======================================================= */
59
60 Distance::Distance(const synfig::String& str)
61 {
62         (*this)=str;
63 /*      int i(0);
64         float val;
65         int ret(strscanf(str,"%f%n",&val,&i));
66         synfig::info("Distance::Distance(): ret=%d, val=%f",ret,val);
67
68         if(ret<=0)
69         {
70                 // Error
71                 synfig::error("Distance::Distance(): Bad value \"%s\"",str.c_str());
72                 value_=0;
73         }
74         else
75                 value_=val;
76
77         synfig::info("Distance::Distance(): system=\"%s\"",String(str.begin()+i,str.end()).c_str());
78         system_=ident_system(String(str.begin()+i,str.end()));
79 */
80 }
81
82 Distance&
83 Distance::operator=(const synfig::String& str)
84 {
85         int i(0);
86         float val;
87         int ret(strscanf(str,"%f%n",&val,&i));
88         // synfig::info("Distance::Distance(): ret=%d, val=%f",ret,val);
89
90         if(ret<=0)
91         {
92                 // Error
93                 synfig::error("Distance::Distance(): Bad value \"%s\"",str.c_str());
94                 return *this;
95         }
96         else
97                 value_=val;
98
99         synfig::String sys(str.begin()+i,str.end());
100
101         if(sys.size())
102                 system_=ident_system(sys);
103         return *this;
104 }
105
106 synfig::String
107 Distance::get_string(int digits)const
108 {
109         digits=min(9,max(0,digits));
110         String fmt(strprintf("%%.%01df%%s",digits));
111         return strprintf(fmt.c_str(),value_,system_name(system_).c_str());
112 }
113
114 void
115 Distance::convert(Distance::System target, const RendDesc& rend_desc)
116 {
117         value_=get(target,rend_desc);
118         system_=target;
119 }
120
121 Real
122 Distance::get(Distance::System target, const RendDesc& rend_desc)const
123 {
124         if(target==SYSTEM_UNITS)
125                 return units(rend_desc);
126         if(target==SYSTEM_PIXELS)
127                 return units(rend_desc)*METERS_PER_UNIT*rend_desc.get_x_res();
128
129         return meters_to_system(meters(rend_desc),target);
130 }
131
132 Real
133 Distance::meters()const
134 {
135         switch(system_)
136         {
137                 case SYSTEM_INCHES:              return value_/INCHES_PER_METER;
138                 case SYSTEM_POINTS:              return value_/POINTS_PER_METER;
139                 case SYSTEM_METERS:              return value_;
140                 case SYSTEM_CENTIMETERS: return value_/CENTIMETERS_PER_METER;
141                 case SYSTEM_MILLIMETERS: return value_/MILLIMETERS_PER_METER;
142                 default: throw BadSystem();
143         }
144 }
145
146 Real
147 Distance::meters(const RendDesc& rend_desc)const
148 {
149         if(system_>SYSTEM_PIXELS)
150                 return meters();
151         if(system_==SYSTEM_UNITS)
152                 return value_*METERS_PER_UNIT;
153         if(system_==SYSTEM_PIXELS)
154                 return value_/rend_desc.get_x_res();
155
156         throw BadSystem();
157 }
158
159 Real
160 Distance::units(const RendDesc& rend_desc)const
161 {
162         if(system_==SYSTEM_UNITS)
163                 return value_;
164
165         Real ret;
166
167         if(system_>SYSTEM_PIXELS)
168                 ret=meters();
169         else
170                 ret=value_/rend_desc.get_x_res();
171
172         return ret/METERS_PER_UNIT;
173 }
174
175
176 Real // (static)
177 Distance::meters_to_system(Real x,System target_system)
178 {
179         switch(target_system)
180         {
181                 case SYSTEM_INCHES:              return x*INCHES_PER_METER;
182                 case SYSTEM_POINTS:              return x*POINTS_PER_METER;
183                 case SYSTEM_METERS:              return x;
184                 case SYSTEM_CENTIMETERS: return x*CENTIMETERS_PER_METER;
185                 case SYSTEM_MILLIMETERS: return x*MILLIMETERS_PER_METER;
186                 default: throw BadSystem();
187         }
188 }
189
190 Distance::System // (static)
191 Distance::ident_system(const synfig::String& x)
192 {
193         synfig::String str;
194
195         // Make it all upper case, and remove white space
196         for(unsigned int i=0;i<x.size();i++)if(x[i]!=' ' && x[i]!='\t')str+=toupper(x[i]);
197
198         // If it is plural, make it singular
199         if(str[str.size()-1]=='S')
200                 str=synfig::String(str.begin(),str.end()-1);
201
202         if(str.empty() || str=="U" || str=="UNIT")
203                 return SYSTEM_UNITS;
204         if(str=="PX" || str=="PIXEL")
205                 return SYSTEM_PIXELS;
206         if(str=="PT" || str=="POINT")
207                 return SYSTEM_POINTS;
208         if(str=="IN" || str=="\"" || str=="INCHE" || str=="INCH")
209                 return SYSTEM_INCHES;
210         if(str=="M" || str=="METER")
211                 return SYSTEM_METERS;
212         if(str=="CM" || str=="CENTIMETER")
213                 return SYSTEM_CENTIMETERS;
214         if(str=="MM" || str=="MILLIMETER")
215                 return SYSTEM_MILLIMETERS;
216
217         synfig::warning("Distance::ident_system(): Unknown distance system \"%s\"",x.c_str());
218
219         return SYSTEM_UNITS;
220 }
221
222 synfig::String  // (static)
223 Distance::system_name(Distance::System system)
224 {
225         switch(system)
226         {
227                 case SYSTEM_UNITS:              return "u";
228                 case SYSTEM_PIXELS:             return "px";
229                 case SYSTEM_POINTS:             return "pt";
230                 case SYSTEM_INCHES:             return "in";
231                 case SYSTEM_METERS:             return "m";
232                 case SYSTEM_MILLIMETERS:        return "mm";
233                 case SYSTEM_CENTIMETERS:        return "cm";
234
235                 default:                                throw BadSystem();
236         }
237         return synfig::String();
238 }
239
240 synfig::String  // (static)
241 Distance::system_local_name(Distance::System system)
242 {
243         switch(system)
244         {
245                 case SYSTEM_UNITS:              return _("Units");
246                 case SYSTEM_PIXELS:             return _("Pixels");
247                 case SYSTEM_POINTS:             return _("Points");
248                 case SYSTEM_INCHES:             return _("Inches");
249                 case SYSTEM_METERS:             return _("Meters");
250                 case SYSTEM_MILLIMETERS:return _("Millimeters");
251                 case SYSTEM_CENTIMETERS:return _("Centimeters");
252
253                 default:                                throw BadSystem();
254         }
255         return synfig::String();
256 }