Back to index

texmacs  1.0.7.15
env_length.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : env_length.cpp
00004 * DESCRIPTION: length computations
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "env.hpp"
00013 #include "convert.hpp"
00014 #include "page_type.hpp"
00015 #include "typesetter.hpp"
00016 
00017 /******************************************************************************
00018 * Length arithmetic
00019 ******************************************************************************/
00020 
00021 bool
00022 edit_env_rep::is_length (string s) {
00023   int i;
00024   for (i=0; (i<N(s)) && ((s[i]<'a') || (s[i]>'z')); i++) {}
00025   return is_double (s (0, i)) && is_locase_alpha (s (i, N(s)));
00026 }
00027 
00028 bool
00029 edit_env_rep::is_anylen (tree t) {
00030   return
00031     (is_func (t, TMLEN) && ((N(t) == 1) || (N(t) == 3))) ||
00032     (is_atomic (t) && is_length (t->label)) ||
00033     is_func (t, MACRO, 1);
00034 }
00035 
00036 tree
00037 edit_env_rep::tmlen_plus (tree t1, tree t2) {
00038   if ((N(t1) == 1) && (N(t2) == 1))
00039     return tree (TMLEN, as_string (as_double (t1[0]) + as_double (t2[0])));
00040   if (N(t1) == 1) t1= tree (TMLEN, t1[0], t1[0], t1[0]);
00041   if (N(t2) == 1) t2= tree (TMLEN, t2[0], t2[0], t2[0]);
00042   if (N(t1) < 3 || N(t2) < 3) return tree (ERROR, "invalid tmlen-plus");
00043   tree _min= as_string (as_double (t1[0]) + as_double (t2[0]));
00044   tree _def= as_string (as_double (t1[1]) + as_double (t2[1]));
00045   tree _max= as_string (as_double (t1[2]) + as_double (t2[2]));
00046   return tree (TMLEN, _min, _def, _max);
00047 }
00048 
00049 tree
00050 edit_env_rep::tmlen_min (tree t1, tree t2) {
00051   if ((N(t1) == 1) && (N(t2) == 1))
00052     return tree (TMLEN, as_string (min (as_double(t1[0]), as_double(t2[0]))));
00053   if (N(t1) == 1) t1= tree (TMLEN, t1[0], t1[0], t1[0]);
00054   if (N(t2) == 1) t2= tree (TMLEN, t2[0], t2[0], t2[0]);
00055   if (N(t1) < 3 || N(t2) < 3) return tree (ERROR, "invalid tmlen-plus");
00056   tree _min= as_string (min (as_double (t1[0]), as_double (t2[0])));
00057   tree _def= as_string (min (as_double (t1[1]), as_double (t2[1])));
00058   tree _max= as_string (min (as_double (t1[2]), as_double (t2[2])));
00059   return tree (TMLEN, _min, _def, _max);
00060 }
00061 
00062 tree
00063 edit_env_rep::tmlen_max (tree t1, tree t2) {
00064   if ((N(t1) == 1) && (N(t2) == 1))
00065     return tree (TMLEN, as_string (max (as_double(t1[0]), as_double(t2[0]))));
00066   if (N(t1) == 1) t1= tree (TMLEN, t1[0], t1[0], t1[0]);
00067   if (N(t2) == 1) t2= tree (TMLEN, t2[0], t2[0], t2[0]);
00068   if (N(t1) < 3 || N(t2) < 3) return tree (ERROR, "invalid tmlen-plus");
00069   tree _min= as_string (max (as_double (t1[0]), as_double (t2[0])));
00070   tree _def= as_string (max (as_double (t1[1]), as_double (t2[1])));
00071   tree _max= as_string (max (as_double (t1[2]), as_double (t2[2])));
00072   return tree (TMLEN, _min, _def, _max);
00073 }
00074 
00075 tree
00076 edit_env_rep::tmlen_times (double sc, tree t) {
00077   if (N(t) == 1) return tree (TMLEN, as_string (sc * as_double (t[0])));
00078   if (N(t) < 3) return tree (ERROR, "invalid tmlen-times");
00079   tree _min= as_string (sc * as_double (t[0]));
00080   tree _def= as_string (sc * as_double (t[1]));
00081   tree _max= as_string (sc * as_double (t[2]));
00082   return tree (TMLEN, _min, _def, _max);
00083 }
00084 
00085 tree
00086 edit_env_rep::tmlen_over (tree t1, tree t2) {
00087   t1= t1[N(t1)==1? 0: 1];
00088   t2= t2[N(t2)==1? 0: 1];
00089   return as_string (as_double (t1) / as_double (t2));
00090 }
00091 
00092 double
00093 edit_env_rep::tmlen_div (tree t1, tree t2) {
00094   t1= t1[N(t1)==1? 0: 1];
00095   t2= t2[N(t2)==1? 0: 1];
00096   return floor ((as_double (t1) / as_double (t2)) + 0.0001);
00097 }
00098 
00099 tree
00100 edit_env_rep::tmlen_mod (tree t1, tree t2) {
00101   double div= tmlen_div (t1, t2);
00102   return tmlen_plus (t1, tmlen_times (-div, t2));
00103 }
00104 
00105 /******************************************************************************
00106 * Length arithmetic for strings
00107 ******************************************************************************/
00108 
00109 void
00110 edit_env_rep::get_length_unit (string s, SI& un, string& un_str) {
00111   int i;
00112   for (i=0; i<N(s); i++)
00113     if ((s[i]>='a') && (s[i]<='z')) break;
00114   un= as_length (string ("1" * s (i, N(s))));
00115   un_str= s (i, N(s));
00116 }
00117 
00118 string
00119 edit_env_rep::add_lengths (string s1, string s2) {
00120   SI l1= as_length (s1);
00121   SI l2= as_length (s2);
00122   SI un; string un_str;
00123   get_length_unit (s1, un, un_str);
00124   if (un==0) return "0tmpt";
00125   double x= ((double) (l1+l2)) / ((double) un);
00126   return as_string (x) * un_str;
00127 }
00128 
00129 string
00130 edit_env_rep::multiply_length (double x, string s) {
00131   SI l= as_length (s);
00132   SI un; string un_str;
00133   get_length_unit (s, un, un_str);
00134   if (un==0) return "0tmpt";
00135   double xl= (x*l) / ((double) un);
00136   return as_string (xl) * un_str;
00137 }
00138 
00139 double
00140 edit_env_rep::divide_lengths (string s1, string s2) {
00141   SI l1= as_length (s1);
00142   SI l2= as_length (s2);
00143   return ((double) l1) / ((double) l2);
00144 }
00145 
00146 /******************************************************************************
00147 * Decoding lengths
00148 ******************************************************************************/
00149 
00150 tree
00151 edit_env_rep::as_tmlen (tree t) {
00152   if (is_func (t, TMLEN)) {
00153     if (N(t) == 0) return t;
00154     if (is_double (t[0])) return t;
00155     if (N(t) < 3) return as_tmlen (t[0]);
00156     tree _min= as_tmlen (t[0]);
00157     tree _def= as_tmlen (t[1]);
00158     tree _max= as_tmlen (t[2]);
00159     if (N(_min) < 1) return t;
00160     if (N(_def) < 1) return t;
00161     if (N(_max) < 1) return t;
00162     _min= _min[N(_min) == 3? 1: 0];
00163     _def= _def[N(_def) == 3? 1: 0];
00164     _max= _max[N(_max) == 3? 1: 0];
00165     return tree (TMLEN, _min, _def, _max);
00166   }
00167   else if (is_atomic (t)) {
00168     string s= t->label;
00169     int start= 0, i, n=N(s);
00170     while ((start+1<n) && (s[start]=='-') && (s[start+1]=='-')) start += 2;
00171     for (i=start; (i<n) && ((s[i]<'a') || (s[i]>'z')); i++) {}
00172     string s1= s (start, i);
00173     string s2= s (i, n);
00174     if (!(is_double (s1) && is_locase_alpha (s2))) return tree (TMLEN, "0");
00175     return tmlen_times (as_double (s1),
00176                      as_tmlen (exec (compound (s2 * "-length"))));
00177   }
00178   else if (is_func (t, MACRO, 1))
00179     return as_tmlen (exec (t[0]));
00180   else return tree (TMLEN, "0");
00181 }
00182 
00183 SI
00184 edit_env_rep::as_length (tree t) {
00185   tree r= as_tmlen (t);
00186   if (N(r) < 1) return 0;
00187   string s= r[N(r)==1? 0: 1]->label;
00188   return (SI) (as_double (s));
00189 }
00190 
00191 SI
00192 edit_env_rep::as_length (tree t, string perc) {
00193   if (is_atomic (t) && N(t->label) > 0 && t->label [N(t->label) - 1] == '%')
00194     return as_length (t->label (0, N(t->label) - 1) * perc) / 100;
00195   else {
00196     tree r= as_tmlen (t);
00197     if (N(r) < 1) return 0;
00198     string s= r[N(r)==1? 0: 1]->label;
00199     return (SI) (as_double (s));
00200   }
00201 }
00202 
00203 space
00204 edit_env_rep::as_hspace (tree t) {
00205   tree r= as_tmlen (t);
00206   if (N(r) == 1)
00207     return space ((SI) (as_double (r[0]->label)));
00208   else if (N(r) < 3)
00209     return 0;
00210   else {
00211     SI _min= (SI) as_double (r[0]->label);
00212     SI _def= (SI) as_double (r[1]->label);
00213     SI _max= (SI) as_double (r[2]->label);
00214     return space (_min, _def, _max);
00215   }
00216 }
00217 
00218 space
00219 edit_env_rep::as_vspace (tree t) {
00220   tree r= as_tmlen (t);
00221   if (N(r) == 1)
00222     return space ((SI) (as_double (r[0]->label)));
00223   else if (N(r) < 3)
00224     return 0;
00225   else {
00226     SI _min= (SI) as_double (r[0]->label);
00227     SI _def= (SI) as_double (r[1]->label);
00228     SI _max= (SI) as_double (r[2]->label);
00229     return space (_def + ((SI) (flexibility * (_min - _def))),
00230                 _def,
00231                 _def + ((SI) (flexibility * (_max - _def))));
00232   }
00233 }
00234 
00235 point
00236 edit_env_rep::as_point (tree t) {
00237   if ((is_tuple (t) || is_point (t)) && ((N(t)==0) || is_double (t[0])))
00238     return ::as_point (t);
00239   if (is_tuple (t) || is_point (t)) {
00240     int i, n= N(t);
00241     point p(n);
00242     for (i=0; i<n; i++)
00243       p[i]= as_length (t[i]);
00244     return fr[p];
00245   }
00246   if (is_func (t, WITH)) {
00247     for (int i=0; i<N(t)-1; i+=2) {
00248       tree var= t[i+1];
00249       if (is_func (var, QUOTE, 1)) var= var[0];
00250       if (t[i] == GID && has_graphical_value (var)) {
00251         tree old_t= t[N(t)-1];
00252         tree new_t= get_graphical_value (var);
00253         if (new_t != old_t) {
00254           point old_p= as_point (old_t);
00255           point new_p= as_point (new_t);
00256           if (new_p != old_p) {
00257             graphics_require_update (var);
00258             return old_p;//return new_p;
00259           }
00260         }
00261       }
00262     }
00263     return as_point (t[N(t)-1]);
00264   }
00265   return point ();
00266 }
00267 
00268 /******************************************************************************
00269 * Percentages and magnifications
00270 ******************************************************************************/
00271 
00272 bool
00273 is_percentage (tree t, string s) {
00274   return
00275     is_atomic (t) &&
00276     ends (t->label, s) &&
00277     is_double (t->label (0, N (t->label) - 1));
00278 }
00279 
00280 bool
00281 is_percentage (tree t) {
00282   return is_percentage (t, "%");
00283 }
00284 
00285 double
00286 as_percentage (tree t) {
00287   return as_double (t->label (0, N (t->label) - 1)) / 100.0;
00288 }
00289 
00290 bool
00291 is_magnification (string s) {
00292   double result;
00293   if (N(s) == 0) return false;
00294   for (int i=0; i<N(s); /*nop*/) {
00295     if (s[i]=='*') { i++; read_double (s, i, result); }
00296     else if (s[i]=='/') { i++; read_double (s, i, result); }
00297     else return false;
00298   }
00299   return true;
00300 }
00301 
00302 double
00303 get_magnification (string s) {
00304   int i=0;
00305   double magn= 1.0, result;
00306   while (i<N(s)) {
00307     if (s[i]=='*') { i++; read_double (s, i, result); magn *= result; }
00308     else if (s[i]=='/') { i++; read_double (s, i, result); magn /= result; }
00309     else return magn;
00310   }
00311   return magn;
00312 }
00313 
00314 /******************************************************************************
00315 * Built-in length units
00316 ******************************************************************************/
00317 
00318 tree edit_env_rep::exec_cm_length () {
00319   return tree (TMLEN, as_string (inch/2.54)); }
00320 tree edit_env_rep::exec_mm_length () {
00321   return tree (TMLEN, as_string (inch/25.4)); }
00322 tree edit_env_rep::exec_in_length () {
00323   return tree (TMLEN, as_string (inch)); }
00324 tree edit_env_rep::exec_pt_length () {
00325   return tree (TMLEN, as_string (inch/72.27)); }
00326 tree edit_env_rep::exec_bp_length () {
00327   return tree (TMLEN, as_string (inch/72.0)); }
00328 tree edit_env_rep::exec_dd_length () {
00329   return tree (TMLEN, as_string (0.376*inch/25.4)); }
00330 tree edit_env_rep::exec_pc_length () {
00331   return tree (TMLEN, as_string (12.0*inch/72.27)); }
00332 tree edit_env_rep::exec_cc_length () {
00333   return tree (TMLEN, as_string (4.531*inch/25.4)); }
00334 
00335 tree
00336 edit_env_rep::exec_fs_length () {
00337   double fs=
00338     (get_int(FONT_BASE_SIZE) * magn * inch * get_double(FONT_SIZE)) / 72.0;
00339   return tree (TMLEN, as_string (fs));
00340 }
00341 
00342 tree
00343 edit_env_rep::exec_fbs_length () {
00344   double fbs= (get_int(FONT_BASE_SIZE) * magn * inch) / 72.0;
00345   return tree (TMLEN, as_string (fbs));
00346 }
00347 
00348 tree edit_env_rep::exec_em_length () {
00349   return tree (TMLEN, as_string (fn->wquad)); }
00350 tree edit_env_rep::exec_ln_length () {
00351   return tree (TMLEN, as_string (fn->wline)); }
00352 tree edit_env_rep::exec_sep_length () {
00353   return tree (TMLEN, as_string (fn->sep)); }
00354 tree edit_env_rep::exec_yfrac_length () {
00355   return tree (TMLEN, as_string (fn->yfrac)); }
00356 tree edit_env_rep::exec_ex_length () {
00357   return tree (TMLEN, as_string (fn->yx)); }
00358 
00359 tree
00360 edit_env_rep::exec_fn_length () {
00361   double fn=
00362     (get_int(FONT_BASE_SIZE) * magn * inch * get_double(FONT_SIZE)) / 72.0;
00363   return tree (TMLEN, as_string (0.5*fn), as_string (fn), as_string (1.5*fn));
00364 }
00365 
00366 tree
00367 edit_env_rep::exec_fns_length () {
00368   double fn=
00369     (get_int(FONT_BASE_SIZE) * magn * inch * get_double(FONT_SIZE)) / 72.0;
00370   return tree (TMLEN, "0", "0", as_string (fn));
00371 }
00372 
00373 tree
00374 edit_env_rep::exec_bls_length () {
00375   double fn=
00376     (get_int(FONT_BASE_SIZE) * magn * inch * get_double(FONT_SIZE)) / 72.0;
00377   return tmlen_plus (tree (TMLEN, as_string (fn)), get_vspace (PAR_SEP));
00378 }
00379 
00380 tree
00381 edit_env_rep::exec_fnbot_length () {
00382   return tree (TMLEN, as_string (fn->y1));
00383 }
00384 
00385 tree
00386 edit_env_rep::exec_fntop_length () {
00387   return tree (TMLEN, as_string (fn->y2));
00388 }
00389 
00390 tree
00391 edit_env_rep::exec_spc_length () {
00392   return tree (TMLEN,
00393               as_string (fn->spc->min),
00394               as_string (fn->spc->def),
00395               as_string (fn->spc->max));
00396 }
00397 
00398 tree
00399 edit_env_rep::exec_xspc_length () {
00400   return tree (TMLEN,
00401               as_string (fn->extra->min),
00402               as_string (fn->extra->def),
00403               as_string (fn->extra->max));
00404 }
00405 
00406 tree
00407 edit_env_rep::exec_par_length () {
00408   SI width, d1, d2, d3, d4, d5, d6, d7;
00409   if (read (PAR_WIDTH) != "auto") {
00410     width= get_length (PAR_WIDTH);
00411     int nr_cols= get_int (PAR_COLUMNS);
00412     if (nr_cols > 1) {
00413       SI col_sep= get_length (PAR_COLUMNS_SEP);
00414       width= ((width+col_sep) / nr_cols) - col_sep;
00415     }
00416   }
00417   else get_page_pars (width, d1, d2, d3, d4, d5, d6, d7);
00418   width -= (get_length (PAR_LEFT) + get_length (PAR_RIGHT));
00419   return tree (TMLEN, as_string (width));
00420 }
00421 
00422 tree
00423 edit_env_rep::exec_pag_length () {
00424   SI d1, height, d2, d3, d4, d5, d6, d7;
00425   get_page_pars (d1, height, d2, d3, d4, d5, d6, d7);
00426   return tree (TMLEN, as_string (height));
00427 }
00428 
00429 tree edit_env_rep::exec_tmpt_length () {
00430   return tree (TMLEN, "1"); }
00431 tree edit_env_rep::exec_px_length () {
00432   return tree (TMLEN, as_string (get_int (SFACTOR) * PIXEL)); }
00433 
00434 tree edit_env_rep::exec_gw_length () {
00435   return tree (TMLEN, as_string (gw)); }
00436 tree edit_env_rep::exec_gh_length () {
00437   return tree (TMLEN, as_string (gh)); }
00438 
00439 tree edit_env_rep::exec_msec_length () { return tree (TMLEN, "1"); }
00440 tree edit_env_rep::exec_sec_length () { return tree (TMLEN, "1000"); }
00441 tree edit_env_rep::exec_min_length () { return tree (TMLEN, "60000"); }
00442 tree edit_env_rep::exec_hr_length () { return tree (TMLEN, "3600000"); }