skydarc meneldoll / Mbed OS test_TFT_11_v5
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers GFX.cpp Source File

GFX.cpp

00001 /*
00002 This is the core graphics library for all our displays, providing a common
00003 set of graphics primitives (points, lines, circles, etc.).  It needs to be
00004 paired with a hardware-specific library for each display device we carry
00005 (to handle the lower-level functions).
00006 
00007 Adafruit invests time and resources providing this open source code, please
00008 support Adafruit & open-source hardware by purchasing products from Adafruit!
00009  
00010 Copyright (c) 2013 Adafruit Industries.  All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014 
00015 - Redistributions of source code must retain the above copyright notice,
00016   this list of conditions and the following disclaimer.
00017 - Redistributions in binary form must reproduce the above copyright notice,
00018   this list of conditions and the following disclaimer in the documentation
00019   and/or other materials provided with the distribution.
00020 
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00025 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00030 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 POSSIBILITY OF SUCH DAMAGE.*/
00032 
00033 /*Modified for MBED usage and tested with STM32F411RE on a Nucleo board.
00034 Embedded Print methods from Arduino Print.Cpp/Print.h
00035 
00036 by James Kidd 2014
00037  * */
00038 
00039 #include <stdint.h>
00040 #include "GFX.h"
00041 #include "font.c"
00042 #include <math.h>
00043 #include <stdlib.h>
00044 #include <stddef.h>
00045  #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
00046 
00047 
00048 GFX::GFX(int16_t w, int16_t h):
00049   WIDTH(w), HEIGHT(h)
00050 {
00051   _width    = WIDTH;
00052   _height   = HEIGHT;
00053   rotation  = 0;
00054   cursor_y  = cursor_x    = 0;
00055   textsize  = 1;
00056   textcolor = textbgcolor = 0xFFFF;
00057   wrap      = true;
00058 }
00059 
00060 // Draw a circle outline
00061 void GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
00062     uint16_t color) {
00063   int16_t f = 1 - r;
00064   int16_t ddF_x = 1;
00065   int16_t ddF_y = -2 * r;
00066   int16_t x = 0;
00067   int16_t y = r;
00068 
00069   drawPixel(x0  , y0+r, color);
00070   drawPixel(x0  , y0-r, color);
00071   drawPixel(x0+r, y0  , color);
00072   drawPixel(x0-r, y0  , color);
00073 
00074   while (x<y) {
00075     if (f >= 0) {
00076       y--;
00077       ddF_y += 2;
00078       f += ddF_y;
00079     }
00080     x++;
00081     ddF_x += 2;
00082     f += ddF_x;
00083   
00084     drawPixel(x0 + x, y0 + y, color);
00085     drawPixel(x0 - x, y0 + y, color);
00086     drawPixel(x0 + x, y0 - y, color);
00087     drawPixel(x0 - x, y0 - y, color);
00088     drawPixel(x0 + y, y0 + x, color);
00089     drawPixel(x0 - y, y0 + x, color);
00090     drawPixel(x0 + y, y0 - x, color);
00091     drawPixel(x0 - y, y0 - x, color);
00092   }
00093 }
00094 
00095 void GFX::drawCircleHelper( int16_t x0, int16_t y0,
00096                int16_t r, uint8_t cornername, uint16_t color) {
00097   int16_t f     = 1 - r;
00098   int16_t ddF_x = 1;
00099   int16_t ddF_y = -2 * r;
00100   int16_t x     = 0;
00101   int16_t y     = r;
00102 
00103   while (x<y) {
00104     if (f >= 0) {
00105       y--;
00106       ddF_y += 2;
00107       f     += ddF_y;
00108     }
00109     x++;
00110     ddF_x += 2;
00111     f     += ddF_x;
00112     if (cornername & 0x4) {
00113       drawPixel(x0 + x, y0 + y, color);
00114       drawPixel(x0 + y, y0 + x, color);
00115     } 
00116     if (cornername & 0x2) {
00117       drawPixel(x0 + x, y0 - y, color);
00118       drawPixel(x0 + y, y0 - x, color);
00119     }
00120     if (cornername & 0x8) {
00121       drawPixel(x0 - y, y0 + x, color);
00122       drawPixel(x0 - x, y0 + y, color);
00123     }
00124     if (cornername & 0x1) {
00125       drawPixel(x0 - y, y0 - x, color);
00126       drawPixel(x0 - x, y0 - y, color);
00127     }
00128   }
00129 }
00130 
00131 void GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
00132                   uint16_t color) {
00133   drawFastVLine(x0, y0-r, 2*r+1, color);
00134   fillCircleHelper(x0, y0, r, 3, 0, color);
00135 }
00136 
00137 // Used to do circles and roundrects
00138 void GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
00139     uint8_t cornername, int16_t delta, uint16_t color) {
00140 
00141   int16_t f     = 1 - r;
00142   int16_t ddF_x = 1;
00143   int16_t ddF_y = -2 * r;
00144   int16_t x     = 0;
00145   int16_t y     = r;
00146 
00147   while (x<y) {
00148     
00149     if (f >= 0) {
00150       y--;
00151       ddF_y += 2;
00152       f     += ddF_y;
00153     }
00154     x++;
00155     ddF_x += 2;
00156     f     += ddF_x;
00157 
00158     if (cornername & 0x1) {
00159       drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
00160       drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
00161     }
00162     if (cornername & 0x2) {
00163       drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
00164       drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
00165     }
00166   }
00167 }
00168 
00169 // Bresenham's algorithm - thx wikpedia
00170 void GFX::drawLine(int16_t x0, int16_t y0,
00171                 int16_t x1, int16_t y1,
00172                 uint16_t color) {
00173   int16_t steep =  abs(y1 - y0) > abs(x1 - x0);
00174   if (steep) {
00175     swap(x0, y0);
00176     swap(x1, y1);
00177   }
00178 
00179   if (x0 > x1) {
00180     swap(x0, x1);
00181     swap(y0, y1);
00182   }
00183 
00184   int16_t dx, dy;
00185   dx = x1 - x0;
00186   dy = abs(y1 - y0);
00187 
00188   int16_t err = dx / 2;
00189   int16_t ystep;
00190 
00191   if (y0 < y1) {
00192     ystep = 1;
00193   } else {
00194     ystep = -1;
00195   }
00196 
00197   for (; x0<=x1; x0++) {
00198     if (steep) {
00199       drawPixel(y0, x0, color);
00200     } else {
00201       drawPixel(x0, y0, color);
00202     }
00203     err -= dy;
00204     if (err < 0) {
00205       y0 += ystep;
00206       err += dx;
00207     }
00208   }
00209 }
00210 
00211 // Draw a rectangle
00212 void GFX::drawRect(int16_t x, int16_t y,
00213                 int16_t w, int16_t h,
00214                 uint16_t color) {
00215   drawFastHLine(x, y, w, color);
00216   drawFastHLine(x, y+h-1, w, color);
00217   drawFastVLine(x, y, h, color);
00218   drawFastVLine(x+w-1, y, h, color);
00219 }
00220 
00221 void GFX::drawFastVLine(int16_t x, int16_t y,
00222                  int16_t h, uint16_t color) {
00223   // Update in subclasses if desired!
00224   drawLine(x, y, x, y+h-1, color);
00225 }
00226 
00227 void GFX::drawFastHLine(int16_t x, int16_t y,
00228                  int16_t w, uint16_t color) {
00229   // Update in subclasses if desired!
00230   drawLine(x, y, x+w-1, y, color);
00231 }
00232 
00233 void GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
00234                 uint16_t color) {
00235   // Update in subclasses if desired!
00236   for (int16_t i=x; i<x+w; i++) {
00237     drawFastVLine(i, y, h, color);
00238   }
00239 }
00240 
00241 void GFX::fillScreen(uint16_t color) {
00242   fillRect(-10, -10, _width+20, _height+20, color);
00243 }
00244 
00245 // Draw a rounded rectangle
00246 void GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
00247   int16_t h, int16_t r, uint16_t color) {
00248   // smarter version
00249   drawFastHLine(x+r  , y    , w-2*r, color); // Top
00250   drawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
00251   drawFastVLine(x    , y+r  , h-2*r, color); // Left
00252   drawFastVLine(x+w-1, y+r  , h-2*r, color); // Right
00253   // draw four corners
00254   drawCircleHelper(x+r    , y+r    , r, 1, color);
00255   drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
00256   drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
00257   drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
00258 }
00259 
00260 // Fill a rounded rectangle
00261 void GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
00262                  int16_t h, int16_t r, uint16_t color) {
00263   // smarter version
00264   fillRect(x+r, y, w-2*r, h, color);
00265 
00266   // draw four corners
00267   fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
00268   fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
00269 }
00270 
00271 // Draw a triangle
00272 void GFX::drawTriangle(int16_t x0, int16_t y0,
00273                 int16_t x1, int16_t y1,
00274                 int16_t x2, int16_t y2, uint16_t color) {
00275   drawLine(x0, y0, x1, y1, color);
00276   drawLine(x1, y1, x2, y2, color);
00277   drawLine(x2, y2, x0, y0, color);
00278 }
00279 
00280 // Fill a triangle
00281 void GFX::fillTriangle ( int16_t x0, int16_t y0,
00282                   int16_t x1, int16_t y1,
00283                   int16_t x2, int16_t y2, uint16_t color) {
00284 
00285   int16_t a, b, y, last;
00286 
00287   // Sort coordinates by Y order (y2 >= y1 >= y0)
00288   if (y0 > y1) {
00289     swap(y0, y1); swap(x0, x1);
00290   }
00291   if (y1 > y2) {
00292     swap(y2, y1); swap(x2, x1);
00293   }
00294   if (y0 > y1) {
00295     swap(y0, y1); swap(x0, x1);
00296   }
00297 
00298   if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
00299     a = b = x0;
00300     if(x1 < a)      a = x1;
00301     else if(x1 > b) b = x1;
00302     if(x2 < a)      a = x2;
00303     else if(x2 > b) b = x2;
00304     drawFastHLine(a, y0, b-a+1, color);
00305     return;
00306   }
00307 
00308   int16_t
00309     dx01 = x1 - x0,
00310     dy01 = y1 - y0,
00311     dx02 = x2 - x0,
00312     dy02 = y2 - y0,
00313     dx12 = x2 - x1,
00314     dy12 = y2 - y1;
00315   int32_t
00316     sa   = 0,
00317     sb   = 0;
00318 
00319   // For upper part of triangle, find scanline crossings for segments
00320   // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
00321   // is included here (and second loop will be skipped, avoiding a /0
00322   // error there), otherwise scanline y1 is skipped here and handled
00323   // in the second loop...which also avoids a /0 error here if y0=y1
00324   // (flat-topped triangle).
00325   if(y1 == y2) last = y1;   // Include y1 scanline
00326   else         last = y1-1; // Skip it
00327 
00328   for(y=y0; y<=last; y++) {
00329     a   = x0 + sa / dy01;
00330     b   = x0 + sb / dy02;
00331     sa += dx01;
00332     sb += dx02;
00333     /* longhand:
00334     a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
00335     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00336     */
00337     if(a > b) swap(a,b);
00338     drawFastHLine(a, y, b-a+1, color);
00339   }
00340 
00341   // For lower part of triangle, find scanline crossings for segments
00342   // 0-2 and 1-2.  This loop is skipped if y1=y2.
00343   sa = dx12 * (y - y1);
00344   sb = dx02 * (y - y0);
00345   for(; y<=y2; y++) {
00346     a   = x1 + sa / dy12;
00347     b   = x0 + sb / dy02;
00348     sa += dx12;
00349     sb += dx02;
00350     /* longhand:
00351     a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
00352     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00353     */
00354     if(a > b) swap(a,b);
00355     drawFastHLine(a, y, b-a+1, color);
00356   }
00357 }
00358 
00359 void GFX::drawBitmap(int16_t x, int16_t y,
00360                   const uint8_t *bitmap, int16_t w, int16_t h,
00361                   uint16_t color) {
00362 
00363   int16_t i, j, byteWidth = (w + 7) / 8;
00364 
00365   for(j=0; j<h; j++) {
00366     for(i=0; i<w; i++ ) {
00367       if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
00368         drawPixel(x+i, y+j, color);
00369       }
00370     }
00371   }
00372 }
00373 
00374 // Draw a 1-bit color bitmap at the specified x, y position from the
00375 // provided bitmap buffer (must be PROGMEM memory) using color as the
00376 // foreground color and bg as the background color.
00377 void GFX::drawBitmap(int16_t x, int16_t y,
00378             const uint8_t *bitmap, int16_t w, int16_t h,
00379             uint16_t color, uint16_t bg) {
00380 
00381   int16_t i, j, byteWidth = (w + 7) / 8;
00382   
00383   for(j=0; j<h; j++) {
00384     for(i=0; i<w; i++ ) {
00385       if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (128 >> (i & 7))) {
00386         drawPixel(x+i, y+j, color);
00387       }
00388       else {
00389         drawPixel(x+i, y+j, bg);
00390       }
00391     }
00392   }
00393 }
00394 
00395 //Draw XBitMap Files (*.xbm), exported from GIMP,
00396 //Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
00397 //C Array can be directly used with this function
00398 void GFX::drawXBitmap(int16_t x, int16_t y,
00399                               const uint8_t *bitmap, int16_t w, int16_t h,
00400                               uint16_t color) {
00401   
00402   int16_t i, j, byteWidth = (w + 7) / 8;
00403   
00404   for(j=0; j<h; j++) {
00405     for(i=0; i<w; i++ ) {
00406       if(pgm_read_byte(bitmap + j * byteWidth + i / 8) & (1 << (i % 8))) {
00407         drawPixel(x+i, y+j, color);
00408       }
00409     }
00410   }
00411 }
00412 
00413 
00414 uint8_t GFX::write(uint8_t c) {
00415 
00416   if (c == '\n') {
00417     cursor_y += textsize*8;
00418     cursor_x  = 0;
00419   } else if (c == '\r') {
00420     // skip em
00421   } else {
00422     drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
00423     cursor_x += textsize*6;
00424     if (wrap && (cursor_x > (_width - textsize*6))) {
00425       cursor_y += textsize*8;
00426       cursor_x = 0;
00427     }
00428   }
00429 
00430   return 1;
00431 
00432 }
00433 
00434 // Draw a character
00435 void GFX::drawChar(int16_t x, int16_t y, unsigned char c,
00436                 uint16_t color, uint16_t bg, uint8_t size) {
00437 
00438   if((x >= _width)            || // Clip right
00439      (y >= _height)           || // Clip bottom
00440      ((x + 6 * size - 1) < 0) || // Clip left
00441      ((y + 8 * size - 1) < 0))   // Clip top
00442     return;
00443 
00444   for (int8_t i=0; i<6; i++ ) {
00445     uint8_t line;
00446     if (i == 5) 
00447       line = 0x0;
00448     else 
00449       line = pgm_read_byte(font+(c*5)+i);
00450     for (int8_t j = 0; j<8; j++) {
00451       if (line & 0x1) {
00452         if (size == 1) // default size
00453           drawPixel(x+i, y+j, color);
00454         else {  // big size
00455           fillRect(x+(i*size), y+(j*size), size, size, color);
00456         } 
00457       } else if (bg != color) {
00458         if (size == 1) // default size
00459           drawPixel(x+i, y+j, bg);
00460         else {  // big size
00461           fillRect(x+i*size, y+j*size, size, size, bg);
00462         }
00463       }
00464       line >>= 1;
00465     }
00466   }
00467 }
00468 
00469 void GFX::setCursor(int16_t x, int16_t y) {
00470   cursor_x = x;
00471   cursor_y = y;
00472 }
00473 
00474 void GFX::setTextSize(uint8_t s) {
00475   textsize = (s > 0) ? s : 1;
00476 }
00477 
00478 void GFX::setTextColor(uint16_t c) {
00479   // For 'transparent' background, we'll set the bg 
00480   // to the same as fg instead of using a flag
00481   textcolor = textbgcolor = c;
00482 }
00483 
00484 void GFX::setTextColor(uint16_t c, uint16_t b) {
00485   textcolor   = c;
00486   textbgcolor = b; 
00487 }
00488 
00489 void GFX::setTextWrap(bool w) {
00490   wrap = w;
00491 }
00492 
00493 uint8_t GFX::getRotation(void) const {
00494   return rotation;
00495 }
00496 
00497 void GFX::setRotation(uint8_t x) {
00498   rotation = (x & 3);
00499   switch(rotation) {
00500    case 0:
00501    case 2:
00502     _width  = WIDTH;
00503     _height = HEIGHT;
00504     break;
00505    case 1:
00506    case 3:
00507     _width  = HEIGHT;
00508     _height = WIDTH;
00509     break;
00510   }
00511 }
00512 
00513 // Return the size of the display (per current rotation)
00514 int16_t GFX::width(void) const {
00515   return _width;
00516 }
00517  
00518 int16_t GFX::height(void) const {
00519   return _height;
00520 }
00521 
00522 void GFX::invertDisplay(bool i) {
00523   // Do nothing, must be subclassed if supported
00524 }
00525 
00526 
00527 //Methods from Print.cpp Arduino
00528 
00529 uint8_t GFX::write(const uint8_t *buffer, uint8_t size)
00530 {
00531     uint8_t n = 0;
00532   while (size--) {
00533     n += write(*buffer++);
00534   }
00535   return n;
00536 }
00537 
00538 uint8_t GFX::print(const char str[])
00539 {
00540   return write(str);
00541 }
00542 
00543 uint8_t GFX::print(char c)
00544 {
00545   return write(c);
00546 }
00547 
00548 uint8_t GFX::print(unsigned char b, int base)
00549 {
00550   return print((unsigned long) b, base);
00551 }
00552 
00553 uint8_t GFX::print(int n, int base)
00554 {
00555   return print((long) n, base);
00556 }
00557 
00558 uint8_t GFX::print(unsigned int n, int base)
00559 {
00560   return print((unsigned long) n, base);
00561 }
00562 
00563 uint8_t GFX::print(long n, int base)
00564 {
00565   if (base == 0) {
00566     return write(n);
00567   } else if (base == 10) {
00568     if (n < 0) {
00569       int t = print('-');
00570       n = -n;
00571       return printNumber(n, 10) + t;
00572     }
00573     return printNumber(n, 10);
00574   } else {
00575     return printNumber(n, base);
00576   }
00577 }
00578 
00579 uint8_t GFX::print(unsigned long n, int base)
00580 {
00581   if (base == 0) return write(n);
00582   else return printNumber(n, base);
00583 }
00584 
00585 uint8_t GFX::print(double n, int digits)
00586 {
00587   return printFloat(n, digits);
00588 }
00589 
00590 
00591 
00592 
00593 
00594 uint8_t GFX::println(void)
00595 {
00596   size_t n = print('\r');
00597   n += print('\n');
00598   return n;
00599 }
00600 
00601 
00602 
00603 uint8_t GFX::println(const char c[])
00604 {
00605   size_t n = print(c);
00606   n += println();
00607   return n;
00608 }
00609 
00610 uint8_t GFX::println(char c)
00611 {
00612   size_t n = print(c);
00613   n += println();
00614   return n;
00615 }
00616 
00617 uint8_t GFX::println(unsigned char b, int numBase)
00618 {
00619   size_t n = print(b, numBase);
00620   n += println();
00621   return n;
00622 }
00623 
00624 uint8_t GFX::println(int num, int base)
00625 {
00626   size_t n = print(num, base);
00627   n += println();
00628   return n;
00629 }
00630 
00631 uint8_t GFX::println(unsigned int num, int base)
00632 {
00633   size_t n = print(num, base);
00634   n += println();
00635   return n;
00636 }
00637 
00638 uint8_t GFX::println(long num, int base)
00639 {
00640   size_t n = print(num, base);
00641   n += println();
00642   return n;
00643 }
00644 
00645 uint8_t GFX::println(unsigned long num, int base)
00646 {
00647   size_t n = print(num, base);
00648   n += println();
00649   return n;
00650 }
00651 
00652 uint8_t GFX::println(double num, int digits)
00653 {
00654   size_t n = print(num, digits);
00655   n += println();
00656   return n;
00657 }
00658 
00659 
00660 
00661 // Private Methods /////////////////////////////////////////////////////////////
00662 
00663 uint8_t GFX::printNumber(unsigned long n, uint8_t base) {
00664   char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
00665   char *str = &buf[sizeof(buf) - 1];
00666 
00667   *str = '\0';
00668 
00669   // prevent crash if called with base == 1
00670   if (base < 2) base = 10;
00671 
00672   do {
00673     unsigned long m = n;
00674     n /= base;
00675     char c = m - base * n;
00676     *--str = c < 10 ? c + '0' : c + 'A' - 10;
00677   } while(n);
00678 
00679   return write(str);
00680 }
00681 
00682 uint8_t GFX::printFloat(double number, uint8_t digits)
00683 {
00684     uint8_t n = 0;
00685 
00686   if (isnan(number)) return print("nan");
00687   if (isinf(number)) return print("inf");
00688   if (number > 4294967040.0) return print ("ovf");  // constant determined empirically
00689   if (number <-4294967040.0) return print ("ovf");  // constant determined empirically
00690 
00691   // Handle negative numbers
00692   if (number < 0.0)
00693   {
00694      n += print('-');
00695      number = -number;
00696   }
00697 
00698   // Round correctly so that print(1.999, 2) prints as "2.00"
00699   double rounding = 0.5;
00700   for (uint8_t i=0; i<digits; ++i)
00701     rounding /= 10.0;
00702 
00703   number += rounding;
00704 
00705   // Extract the integer part of the number and print it
00706   unsigned long int_part = (unsigned long)number;
00707   double remainder = number - (double)int_part;
00708   n += print(int_part);
00709 
00710   // Print the decimal point, but only if there are digits beyond
00711   if (digits > 0) {
00712     n += print(".");
00713   }
00714 
00715   // Extract digits from the remainder one at a time
00716   while (digits-- > 0)
00717   {
00718     remainder *= 10.0;
00719     int toPrint = int(remainder);
00720     n += print(toPrint);
00721     remainder -= toPrint;
00722   }
00723 
00724   return n;
00725 }
00726 
00727