Back to index

texmacs  1.0.7.15
math_boxes.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : math.cpp
00004 * DESCRIPTION: Boxes for mathematical typesetting:
00005 *              fractions, roots, negations, limits and scripts
00006 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00007 *******************************************************************************
00008 * This software falls under the GNU general public license version 3 or later.
00009 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00010 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00011 ******************************************************************************/
00012 
00013 #include "Boxes/composite.hpp"
00014 #include "Boxes/construct.hpp"
00015 #include "Boxes/Composite/italic_correct.hpp"
00016 
00017 /******************************************************************************
00018 * Miscellaneous routines
00019 ******************************************************************************/
00020 
00021 inline void left_italic_correct (box b) { b->x1 -= b->left_correction (); }
00022 inline void left_italic_restore (box b) { b->x1 += b->left_correction (); }
00023 inline void right_italic_correct (box b) { b->x2 += b->right_correction (); }
00024 inline void right_italic_restore (box b) { b->x2 -= b->right_correction (); }
00025 
00026 SI
00027 italic_correction (box L, box R) {
00028   double slope_L= L->right_slope ();
00029   double slope_R= R->left_slope ();
00030   if (slope_L == slope_R) return 0;
00031   if (slope_L * slope_R == 0.0)
00032     return L->right_correction () + R->left_correction ();
00033   double M= (slope_L <= slope_R? slope_R: slope_L);
00034   if (M<0) M= (slope_L >= slope_R? slope_R: slope_L);
00035   double factor= (slope_R- slope_L) / M;
00036   if (factor < 0) factor= -factor;
00037   return (SI) (factor * (L->right_correction () + R->left_correction ()));
00038 }
00039 
00040 /******************************************************************************
00041 * Fractions
00042 ******************************************************************************/
00043 
00044 struct frac_box_rep: public composite_box_rep {
00045   frac_box_rep (path ip, box b1, box b2, font fn, font sfn, color c);
00046   operator tree () { return tree (TUPLE, "frac", bs[0], bs[1]); }
00047   int find_child (SI x, SI y, SI delta, bool force);
00048 };
00049 
00050 frac_box_rep::frac_box_rep (
00051   path ip, box b1, box b2, font fn, font sfn, color c):
00052     composite_box_rep (ip)
00053 {
00054   // Italic correction does not lead to nicer results,
00055   // because right correction is not equilibrated w.r.t. left correction
00056 
00057   SI bar_y = fn->yfrac;
00058   SI bar_w = fn->wline;
00059   SI sep   = fn->sep;
00060   SI b1_y  = min (b1->y1, sfn->y1);
00061   SI b2_y  = max (b2->y2, sfn->y2);
00062   SI w     = max (b1->w (), b2->w()) + 2*sep;
00063   SI d     = sep >> 1;
00064 
00065   insert (b1, (w>>1) - (b1->x2>>1), bar_y+ sep+ (bar_w>>1)- b1_y);
00066   insert (b2, (w>>1) - (b2->x2>>1), bar_y- sep- (bar_w>>1)- b2_y);
00067   insert (line_box (decorate_middle (ip), d, 0, w-d, 0, bar_w, c), 0, bar_y);
00068 
00069   italic_correct (b1);
00070   italic_correct (b2);
00071   position ();
00072   italic_restore (b1);
00073   italic_restore (b2);
00074   x1= min (0, x1);
00075   x2= max (w, x2);
00076   left_justify ();
00077   finalize ();
00078 }
00079 
00080 int
00081 frac_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00082   if (outside (x, delta, x1, x2) && (is_accessible (ip) || force)) return -1;
00083   int i= (y >= sy(2))? 0: 1;
00084   if (bs[i]->decoration () && (!force)) {
00085     i= 1-i;
00086     if (bs[i]->decoration () && (!force)) return -1;
00087   }
00088   return i;
00089 }
00090 
00091 /******************************************************************************
00092 * Square roots
00093 ******************************************************************************/
00094 
00095 struct sqrt_box_rep: public composite_box_rep {
00096   sqrt_box_rep (path ip, box b1, box b2, box sqrtb, font fn, color c);
00097   operator tree () { return tree (TUPLE, "sqrt", bs[0]); }
00098   int find_child (SI x, SI y, SI delta, bool force);
00099 };
00100 
00101 sqrt_box_rep::sqrt_box_rep (
00102   path ip, box b1, box b2, box sqrtb, font fn, color c):
00103     composite_box_rep (ip)
00104 {
00105   right_italic_correct (b1);
00106 
00107   SI sep  = fn->sep;
00108   SI wline= fn->wline;
00109   SI dx   = -fn->wfn/36, dy= -fn->wfn/36; // correction
00110   SI by   = sqrtb->y2+ dy;
00111 
00112   insert (b1, 0, 0);
00113   if (!is_nil (b2)) {
00114     SI X = - sqrtb->w();
00115     SI M = X / 3;
00116     SI Y = sqrtb->y1;
00117     SI bw= sqrtb->w();
00118     SI bh= sqrtb->h();
00119     if (bh < 3*bw) Y += bh >> 1;
00120     else Y += (bw*3) >> 1;
00121     insert (b2, min (X, M- b2->x2), Y- b2->y1+ sep);
00122   }
00123   insert (sqrtb, -sqrtb->x2, 0);
00124   insert (line_box (decorate_middle (ip), dx, by, b1->x2, by, wline, c), 0, 0);
00125   
00126   position ();
00127   left_justify ();
00128   y1 -= wline;
00129   y2 += wline;
00130   x2 += sep >> 1;
00131 
00132   right_italic_restore (b1);
00133   finalize ();
00134 }
00135 
00136 int
00137 sqrt_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00138   (void) y;
00139   if (outside (x, delta, x1, x2) && (is_accessible (ip) || force)) return -1;
00140   int i= ((N(bs)==3) || (x>sx(0)) || ((x>=sx(0)) && (delta>=0)))? 0: 1;
00141   if (bs[i]->decoration () && (!force)) {
00142     i= 1-i;
00143     if (bs[i]->decoration () && (!force)) return -1;
00144   }
00145   return i;
00146 }
00147 
00148 /******************************************************************************
00149 * Negation boxes
00150 ******************************************************************************/
00151 
00152 struct neg_box_rep: public composite_box_rep {
00153   neg_box_rep (path ip, box b1, font fn, color c);
00154   operator tree () { return tree (TUPLE, "neg", bs[0]); }
00155   int find_child (SI x, SI y, SI delta, bool force);
00156 };
00157 
00158 neg_box_rep::neg_box_rep (path ip, box b, font fn, color c):
00159   composite_box_rep (ip)
00160 {
00161   SI wline= fn->wline;
00162   SI delta= fn->wfn/6;
00163   SI X    = (b->x1 + b->x2) >> 1;
00164   SI Y    = (b->y1 + b->y2) >> 1;
00165   SI DX, DY;
00166 
00167   insert (b, 0, 0);
00168   if ((3*(b->x2-b->x1)) > (2*(b->y2-b->y1))) {
00169     DY= delta + ((b->y2 - b->y1)>>1);
00170     DX= DY>>1;
00171   }
00172   else {
00173     DX= delta + ((b->x2 - b->x1)>>1);
00174     DY= DX;
00175   }
00176   insert (line_box (decorate_middle (ip),
00177                   X+DX, Y+DY, X-DX, Y-DY, wline, c), 0, 0);
00178   
00179   italic_correct (b);
00180   position ();
00181   italic_restore (b);
00182   finalize ();
00183 }
00184 
00185 int
00186 neg_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00187   (void) y;
00188   if (outside (x, delta, x1, x2) && (is_accessible (ip) || force)) return -1;
00189   if (bs[0]->decoration () && (!force)) return -1;
00190   return 0;
00191 }
00192 
00193 /******************************************************************************
00194 * Tree boxes
00195 ******************************************************************************/
00196 
00197 struct tree_box_rep: public composite_box_rep {
00198   SI  border;
00199   tree_box_rep (path ip, array<box> bs, font fn, color line_c);
00200   operator tree () { return "tree box"; }
00201   int find_child (SI x, SI y, SI delta, bool force);
00202 };
00203 
00204 tree_box_rep::tree_box_rep (path ip, array<box> bs, font fn, color line_c):
00205   composite_box_rep (ip)
00206 {
00207   SI sep   = fn->sep;
00208   SI hsep  = 2*fn->spc->def;
00209   SI vsep  = 4*fn->spc->def;
00210   SI line_w= fn->wline;
00211 
00212   int i, n= N(bs), cw, w= 0, h= MIN_SI, x, x_0, up;
00213   for (i=1; i<n; i++) w += bs[i]->w();
00214   for (i=1; i<n; i++) h  = max (h, max (bs[i]->y2, fn->y2) + sep);
00215   w += (n-2)*hsep;
00216   cw = w;
00217   x_0= 0; if (bs[0]->w()>w) { x_0= (bs[0]->w()-w)>>1; w= bs[0]->w(); }
00218   up= min (bs[0]->y1, fn->y1) - sep - vsep;
00219 
00220   insert (bs[0], (w>>1)- ((bs[0]->x1+bs[0]->x2)>>1), 0);
00221   for (x=x_0, i=1; i<n; i++) {
00222     SI x_i= x- bs[i]->x1;
00223     SI y_i= up- h;
00224     insert (bs[i], x_i, y_i);
00225     x += bs[i]->w()+ hsep;
00226   }
00227 
00228   for (x=x_0, i=1; i<n; i++) {
00229     SI x_i= x + (bs[i]->w()>>1);
00230     SI y_i= up + max (bs[i]->y2, fn->y2) + sep - h;
00231     SI bm = w>>1;
00232     SI bw = min (bs[0]->w(), cw>>1);
00233     SI bx = bm + ((2*i-n) * bw) / (2*n-2);
00234     SI by = min (bs[0]->y1, fn->y1) - sep;
00235     insert (line_box (decorate_middle (ip),
00236                     bx, by, x_i, y_i, line_w, line_c), 0, 0);
00237     x += bs[i]->w()+ hsep;
00238   }
00239 
00240   position ();
00241   border= up+ (vsep>>1);
00242   finalize ();
00243 }
00244 
00245 int
00246 tree_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00247   if (outside (x, delta, x1, x2) && (is_accessible (ip) || force)) return -1;
00248   int i=0;
00249   if (y < border) {
00250     int j, d=MAX_SI;
00251     for (j=1; j<((N(bs)+1)>>1); j++)
00252       if (distance (j, x, y, delta)< d)
00253        if (bs[j]->accessible () || force) {
00254          d= distance (j, x, y, delta);
00255          i= j;
00256        }
00257   }
00258   if (bs[i]->decoration () && (!force)) return -1;
00259   return i;
00260 }
00261 
00262 /******************************************************************************
00263 * wide hats, tildas, etc...
00264 ******************************************************************************/
00265 
00266 struct wide_box_rep: public composite_box_rep {
00267   box ref;
00268   SI  dw, dh, dd;
00269   bool above;
00270   wide_box_rep (path ip, box ref, box hi, font fn, SI sep, bool above);
00271   operator tree () { return tree (TUPLE, "wide", bs[0]); }
00272   int find_child (SI x, SI y, SI delta, bool force);
00273   double left_slope ();
00274   double right_slope ();
00275 
00276   SI left_correction () {
00277     return ref->left_correction (); }
00278   SI right_correction () {
00279     if (above) {
00280       SI rc= ref->right_correction () + dw;
00281       if (sx4 (1) >= (sx2 (1) - (dd>>1))) // corrects buggy extents wide chars
00282        rc= max (rc, sx2(1)- x2+ dd);
00283       return rc; }
00284     return ref->right_correction (); }
00285   SI lsub_correction () {
00286     return ref->lsub_correction (); }
00287   SI lsup_correction () {
00288     return ref->lsup_correction (); }
00289   SI rsub_correction () {
00290     return ref->rsub_correction (); }
00291   SI rsup_correction () {
00292     if (above) {
00293       SI rc= ref->rsup_correction () + dw;
00294       if (sx4 (1) >= (sx2 (1) - (dd>>1))) // corrects buggy extents wide chars
00295        rc= max (rc, sx2(1)- x2+ dd);
00296       return rc; }
00297     return ref->rsub_correction (); }
00298   SI sub_lo_base (int level) {
00299     return ref->sub_lo_base (level); }
00300   SI sub_hi_lim  (int level) {
00301     return ref->sub_hi_lim (level); }
00302   SI sup_lo_lim  (int level) {
00303     if (!above)
00304       return max (ref->sup_lo_lim (level) - dh, box_rep::sup_lo_lim (level));
00305     return ref->sup_lo_lim (level); }
00306   SI sup_lo_base (int level) {
00307     return ref->sup_lo_base (level); }
00308   SI sup_hi_lim  (int level) {
00309     if (above)
00310       return min (ref->sup_hi_lim (level) + dh, box_rep::sup_hi_lim (level));
00311     return ref->sup_hi_lim (level); }
00312 };
00313 
00314 wide_box_rep::wide_box_rep (
00315   path ip, box ref2, box hi, font fn, SI sep, bool above2):
00316     composite_box_rep (ip), ref (ref2), above (above2)
00317 {
00318   SI X, Y, dx;
00319   SI hw= max (ref->w(), hi->w()) >> 1;
00320   SI m = (ref->x1 + ref->x2) >> 1;
00321   insert (ref, 0, 0);
00322   if (above) {
00323     Y= ref->y2;
00324     X= ((SI) (ref->right_slope () * Y)) + m;
00325     insert (hi, X- ((hi->x1 + hi->x2)>>1), Y+ sep);
00326   }
00327   else {
00328     Y= ref->y1 - hi->y2;
00329     X= ((SI) (ref->right_slope () * (Y - sep))) + m;
00330     insert (hi, X- ((hi->x1 + hi->x2)>>1), Y- sep);
00331   }
00332   position ();
00333   dx= x1;
00334   left_justify ();
00335 
00336   dh= hi->y2+ sep;
00337   dw= (SI) (dh * ref->right_slope ());
00338   dd= fn->sep;
00339   x1= m- hw- dx;
00340   x2= m+ hw- dx;
00341   if (!above) y1 += fn->sep - sep;
00342   finalize ();
00343 }
00344 
00345 int
00346 wide_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00347   (void) y;
00348   if (outside (x, delta, x1, x2) && (is_accessible (ip) || force)) return -1;
00349   if (bs[0]->decoration () && (!force)) return -1;
00350   return 0;
00351 }
00352 
00353 double
00354 wide_box_rep::left_slope () {
00355   return ref->left_slope ();
00356 }
00357 
00358 double
00359 wide_box_rep::right_slope () {
00360   return ref->right_slope ();
00361 }
00362 
00363 /******************************************************************************
00364 * box construction routines
00365 ******************************************************************************/
00366 
00367 box
00368 frac_box (path ip, box b1, box b2, font fn, font sfn, color c) {
00369   return tm_new<frac_box_rep> (ip, b1, b2, fn, sfn, c);
00370 }
00371 
00372 box
00373 sqrt_box (path ip, box b1, box b2, box sqrtb, font fn, color c) {
00374   return tm_new<sqrt_box_rep> (ip, b1, b2, sqrtb, fn, c);
00375 }
00376 
00377 box
00378 neg_box (path ip, box b, font fn, color c) {
00379   return tm_new<neg_box_rep> (ip, b, fn, c);
00380 }
00381 
00382 box
00383 tree_box (path ip, array<box> bs, font fn, color line_c) {
00384   return tm_new<tree_box_rep> (ip, bs, fn, line_c);
00385 }
00386 
00387 box
00388 wide_box (path ip, box ref, box hi, font fn, SI sep, bool above) {
00389   return tm_new<wide_box_rep> (ip, ref, hi, fn, sep, above);
00390 }