00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef IXLIB_DRAWING_FUNCTIONS
00011 #define IXLIB_DRAWING_FUNCTIONS
00012
00013
00014
00015
00016 #include <ixlib_polygon.hh>
00017
00018
00019
00020
00021 namespace ixion {
00034 namespace drawing_functions {
00042 template<class Target>
00043 void drawLine(Target &target,int x1,int y1,int x2,int y2);
00044
00045 template<class Target>
00046 void drawBox(Target &target,int x1,int y1,int x2,int y2);
00047 template<class Target>
00048 void fillBox(Target &target,int x1,int y1,int x2,int y2);
00049
00050 template<class Target>
00051 void drawCircle(Target &target,int x,int y,int r);
00052 template<class Target>
00053 void fillCircle(Target &target,int x,int y,int r);
00054
00055 template<class Target>
00056 void drawEllipse(Target &target,int x,int y,int r_x,int r_y);
00057 template<class Target>
00058 void fillEllipse(Target &target,int x,int y,int r_x,int r_y);
00059
00060 template<class Target,class T>
00061 void drawPolygon(Target &target,polygon<T> const &poly);
00062 template<class Target,class T>
00063 void fillPolygon(Target &target,polygon<T> const &poly);
00064 }
00065 }
00066
00067
00068
00069
00070
00071 template<class Target>
00072 void ixion::drawing_functions::drawLine(Target &target,int x1,int y1,int x2,int y2) {
00073 int dx = abs(x2-x1);
00074 int dy = abs(y2-y1);
00075 int npixel;
00076 int dinc1;
00077 int dinc2;
00078 int xinc1;
00079 int xinc2;
00080 int yinc1;
00081 int yinc2;
00082 int x;
00083 int y;
00084 int d;
00085
00086 if (dx >= dy) {
00087 npixel = dx;
00088 d = (2*dy)-dx;
00089 dinc1 = dy << 1;
00090 dinc2 = (dy-dx) << 1;
00091 xinc1 = 1;
00092 xinc2 = 1;
00093 yinc1 = 0;
00094 yinc2 = 1;
00095 }
00096 else {
00097 npixel = dy;
00098 d = (2*dx)-dy;
00099 dinc1 = dx << 1;
00100 dinc2 = (dx-dy) << 1;
00101 xinc1 = 0;
00102 xinc2 = 1;
00103 yinc1 = 1;
00104 yinc2 = 1;
00105 }
00106
00107 if (x1>x2) {
00108 xinc1 = -xinc1;
00109 xinc2 = -xinc2;
00110 }
00111 if (y1>y2) {
00112 yinc1 = -yinc1;
00113 yinc2 = -yinc2;
00114 }
00115
00116 x = x1;
00117 y = y1;
00118 for (int i=0; i < npixel; i++) {
00119 target.setPixel(x,y);
00120 if (d<0) {
00121 d += dinc1;
00122 x += xinc1;
00123 y += yinc1;
00124 }
00125 else {
00126 d += dinc2;
00127 x += xinc2;
00128 y += yinc2;
00129 }
00130 }
00131 }
00132
00133
00134
00135
00136 template<class Target>
00137 void ixion::drawing_functions::drawBox(Target &target,int x1,int y1,int x2,int y2) {
00138 target.drawHLine(x1,y1,x2);
00139 target.drawVLine(x1,y1+1,y2);
00140 target.drawHLine(x1,y2,x2);
00141 target.drawVLine(x2-1,y1+1,y2);
00142 }
00143
00144
00145
00146
00147 template<class Target>
00148 void ixion::drawing_functions::fillBox(Target &target,int x1,int y1,int x2,int y2) {
00149 for (int y = y1;y < y2;y++)
00150 target.drawHLine(x1,y,x2);
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 template<class Target>
00166 void ixion::drawing_functions::drawCircle(Target &target,int x,int y,int r) {
00167 int counter = r;
00168 int xcount = 0;
00169 int ycount = r;
00170
00171 target.setPixel(x + xcount,y - ycount);
00172 target.setPixel(x - xcount,y + ycount);
00173 target.setPixel(x - ycount,y - xcount);
00174 target.setPixel(x + ycount,y + xcount);
00175
00176 counter -= xcount + xcount + 1;
00177 xcount++;
00178
00179 while(xcount < ycount) {
00180 if (counter < 0) {
00181 ycount--;
00182 counter += ycount + ycount;
00183 }
00184
00185 target.setPixel(x + xcount,y - ycount);
00186 target.setPixel(x - xcount,y - ycount);
00187 target.setPixel(x + xcount,y + ycount);
00188 target.setPixel(x - xcount,y + ycount);
00189 target.setPixel(x + ycount,y - xcount);
00190 target.setPixel(x - ycount,y - xcount);
00191 target.setPixel(x + ycount,y + xcount);
00192 target.setPixel(x - ycount,y + xcount);
00193
00194 counter -= xcount + xcount + 1;
00195 xcount++;
00196 }
00197 }
00198
00199
00200
00201
00202 template<class Target>
00203 void ixion::drawing_functions::fillCircle(Target &target,int x,int y,int r) {
00204 int counter = r;
00205 int xcount = 0;
00206 int ycount = r;
00207 bool ycount_changed = true;
00208
00209 target.drawHLine(x - ycount,y - xcount,x + ycount);
00210 counter -= xcount + xcount + 1;
00211 xcount++;
00212
00213 while(xcount < ycount) {
00214 if (counter < 0) {
00215 ycount--;
00216 ycount_changed = true;
00217
00218 counter += ycount + ycount;
00219 }
00220
00221 if (ycount_changed) {
00222 target.drawHLine(x - xcount,y - ycount,x + xcount);
00223 target.drawHLine(x - xcount,y + ycount,x + xcount);
00224 ycount_changed = false;
00225 }
00226 target.drawHLine(x - ycount,y - xcount,x + ycount);
00227 target.drawHLine(x - ycount,y + xcount,x + ycount);
00228 counter -= xcount + xcount + 1;
00229 xcount++;
00230 }
00231 }
00232
00233
00234
00235
00236 template<class Target>
00237 void ixion::drawing_functions::drawEllipse(Target &target,int x,int y,int r_x,int r_y) {
00238 int const fix_digits = 10;
00239
00240 if (r_x > r_y) {
00241 int counter = r_x;
00242 int xcount = 0;
00243 int ycount = r_x;
00244 int factor = (r_y << fix_digits) / r_x;
00245
00246 target.setPixel(x + r_x,y);
00247 target.setPixel(x - r_x,y);
00248 target.setPixel(x,y - r_y);
00249 target.setPixel(x,y + r_y);
00250
00251 int lastline_ycount = ycount;
00252 int last_xcount_scaled = (xcount * factor) >> fix_digits;
00253 counter -= xcount + xcount + 1;
00254 xcount++;
00255
00256 while(xcount < ycount) {
00257 if (counter < 0) {
00258 ycount--;
00259 counter += ycount + ycount;
00260 }
00261
00262 int ycount_scaled = (ycount * factor) >> fix_digits;
00263
00264 target.setPixel(x + xcount,y - ycount_scaled);
00265 target.setPixel(x - xcount,y - ycount_scaled);
00266 target.setPixel(x + xcount,y + ycount_scaled);
00267 target.setPixel(x - xcount,y + ycount_scaled);
00268
00269 int xcount_scaled = (xcount * factor) >> fix_digits;
00270
00271 if (xcount_scaled != last_xcount_scaled) {
00272 if (lastline_ycount == ycount) {
00273 target.setPixel(x + ycount,y + xcount_scaled);
00274 target.setPixel(x - ycount,y + xcount_scaled);
00275 target.setPixel(x + ycount,y - xcount_scaled);
00276 target.setPixel(x - ycount,y - xcount_scaled);
00277 }
00278 else {
00279 target.drawHLine(x + ycount,y + xcount_scaled,x + lastline_ycount);
00280 target.drawHLine(x - lastline_ycount + 1,y + xcount_scaled,x - ycount + 1);
00281 target.drawHLine(x + ycount,y - xcount_scaled,x + lastline_ycount);
00282 target.drawHLine(x - lastline_ycount + 1,y - xcount_scaled,x - ycount + 1);
00283 }
00284
00285 last_xcount_scaled = xcount_scaled;
00286 lastline_ycount = ycount;
00287 }
00288
00289 counter -= xcount + xcount + 1;
00290 xcount++;
00291 }
00292 }
00293 else {
00294 int counter = r_y;
00295 int xcount = 0;
00296 int ycount = r_y;
00297 int factor = (r_x << fix_digits) / r_y;
00298
00299 target.setPixel(x + r_x,y);
00300 target.setPixel(x - r_x,y);
00301 target.setPixel(x,y - r_y);
00302 target.setPixel(x,y + r_y);
00303
00304 int lastline_ycount = ycount;
00305 int last_xcount_scaled = (xcount * factor) >> fix_digits;
00306 counter -= xcount + xcount + 1;
00307 xcount++;
00308
00309 while(xcount < ycount) {
00310 if (counter < 0) {
00311 ycount--;
00312 counter += ycount + ycount;
00313 }
00314
00315 int ycount_scaled = (ycount * factor) >> fix_digits;
00316
00317 target.setPixel(x + ycount_scaled,y - xcount);
00318 target.setPixel(x - ycount_scaled,y - xcount);
00319 target.setPixel(x + ycount_scaled,y + xcount);
00320 target.setPixel(x - ycount_scaled,y + xcount);
00321
00322 int xcount_scaled = (xcount * factor) >> fix_digits;
00323
00324 if (xcount_scaled != last_xcount_scaled) {
00325 if (lastline_ycount == ycount) {
00326 target.setPixel(x + xcount_scaled,y + ycount);
00327 target.setPixel(x + xcount_scaled,y - ycount);
00328 target.setPixel(x - xcount_scaled,y + ycount);
00329 target.setPixel(x - xcount_scaled,y - ycount);
00330 }
00331 else {
00332 target.drawVLine(x + xcount_scaled,y + ycount,y + lastline_ycount);
00333 target.drawVLine(x + xcount_scaled,y - lastline_ycount + 1,y - ycount + 1);
00334 target.drawVLine(x - xcount_scaled,y + ycount,y + lastline_ycount);
00335 target.drawVLine(x - xcount_scaled,y - lastline_ycount + 1,y - ycount + 1);
00336 }
00337
00338 last_xcount_scaled = xcount_scaled;
00339 lastline_ycount = ycount;
00340 }
00341
00342 counter -= xcount + xcount + 1;
00343 xcount++;
00344 }
00345 }
00346 }
00347
00348
00349
00350
00351 template<class Target>
00352 void ixion::drawing_functions::fillEllipse(Target &target,int x,int y,int r_x,int r_y) {
00353 int const fix_digits = 10;
00354 if (r_x > r_y) {
00355 int counter = r_x;
00356 int xcount = 0;
00357 int ycount = r_x;
00358 int factor = (r_y << fix_digits) / r_x;
00359
00360 int last_scaled_xcount = (xcount * factor) >> fix_digits;
00361 int last_scaled_ycount = (ycount * factor) >> fix_digits;
00362
00363 target.drawHLine(x - r_x,y,x + r_x + 1);
00364
00365 counter -= xcount + xcount + 1;
00366 xcount ++;
00367
00368 while(xcount < ycount) {
00369 if (counter < 0) {
00370 ycount --;
00371 counter += ycount + ycount;
00372 }
00373
00374 int scaled_xcount = (xcount * factor) >> fix_digits;
00375 int scaled_ycount = (ycount * factor) >> fix_digits;
00376
00377 if (scaled_xcount != scaled_ycount && last_scaled_ycount != scaled_ycount) {
00378 target.drawHLine(x - xcount,y - scaled_ycount,x + xcount+1);
00379 target.drawHLine(x - xcount,y + scaled_ycount,x + xcount+1);
00380 last_scaled_ycount = scaled_ycount;
00381 }
00382 if (last_scaled_xcount != scaled_xcount) {
00383 target.drawHLine(x - ycount,y - scaled_xcount,x + ycount+1);
00384 target.drawHLine(x - ycount,y + scaled_xcount,x + ycount+1);
00385 last_scaled_xcount = scaled_xcount;
00386 }
00387
00388 counter -= xcount + xcount + 1;
00389 xcount ++;
00390 }
00391 }
00392 else {
00393 int counter = r_y;
00394 int xcount = 0;
00395 int ycount = r_y;
00396 int factor = (r_x << fix_digits) / r_y;
00397
00398 int last_scaled_xcount = (xcount * factor) >> fix_digits;
00399 int last_scaled_ycount = (ycount * factor) >> fix_digits;
00400
00401 target.drawVLine(x,y - r_y,y + r_y + 1);
00402
00403 counter -= xcount + xcount + 1;
00404 xcount ++;
00405
00406 while(xcount < ycount) {
00407 if (counter < 0) {
00408 ycount --;
00409 counter += ycount + ycount;
00410 }
00411
00412 int scaled_xcount = (xcount * factor) >> fix_digits;
00413 int scaled_ycount = (ycount * factor) >> fix_digits;
00414
00415 if (scaled_xcount != scaled_ycount && last_scaled_ycount != scaled_ycount) {
00416 target.drawVLine(x + scaled_ycount,y - xcount,y + xcount + 1);
00417 target.drawVLine(x - scaled_ycount,y - xcount,y + xcount + 1);
00418 last_scaled_ycount = scaled_ycount;
00419 }
00420 if (last_scaled_xcount != scaled_xcount) {
00421 target.drawVLine(x + scaled_xcount,y - ycount,y + ycount + 1);
00422 target.drawVLine(x - scaled_xcount,y - ycount,y + ycount + 1);
00423 last_scaled_xcount = scaled_xcount;
00424 }
00425
00426 counter -= xcount + xcount + 1;
00427 xcount ++;
00428 }
00429 }
00430 }
00431
00432
00433
00434
00435 template<class Target,class T>
00436 void ixion::drawing_functions::drawPolygon(Target &target,polygon<T> const &poly) {
00437 FOREACH_CONST(first_seg,poly,polygon<T>) {
00438 if ((*first_seg)->size() <= 1) continue;
00439 if ((*first_seg)->size() == 2) {
00440 drawLine(target,(*first_seg)->front()[0],(*first_seg)->front()[1],
00441 (*first_seg)->back()[0],(*first_seg)->back()[1]);
00442 target.setPixel((*first_seg)->back()[0],(*first_seg)->back()[1]);
00443 }
00444
00445
00446 polygon_segment<T>::const_iterator
00447 next = (*first_seg)->begin(),
00448 last = (*first_seg)->end(),
00449 previous = last-1;
00450 while (next != last) {
00451 drawLine(target,(*previous)[0],(*previous)[1],
00452 (*next)[0],(*next)[1]);
00453 previous = next;
00454 next++;
00455 }
00456 }
00457 }
00458
00459
00460
00461
00462 namespace {
00463 template<class Target>
00464 class hline_routine {
00465 Target &Tgt;
00466 public:
00467 hline_routine(Target &tgt)
00468 : Tgt(tgt) {
00469 }
00470 void operator()(int x1,int y,int x2) const {
00471 Tgt.drawHLine(x1,y,x2);
00472 }
00473 };
00474 }
00475
00476
00477
00478
00479 template<class Target,class T>
00480 void ixion::drawing_functions::fillPolygon(Target &target,polygon<T> const &poly) {
00481 hline_routine<Target> hlr(target);
00482 poly.drawScanlines(hlr);
00483 }
00484
00485
00486
00487
00488 #endif