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