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