00001
00002
00003 char *axis_cpp = "$Id: sxy_axis.cpp,v 1.7 2003/03/10 19:27:11 clinio Exp $";
00004
00005
00006
00007 #include <math.h>
00008 #include <float.h>
00009
00010 extern "C" {
00011 #include <iup.h>
00012 #include <cd.h>
00013 #include <cdiup.h>
00014 }
00015
00016 #include "sxy_chart.h"
00017 #include "sxy_axis.h"
00018 #include "sxy_utils.h"
00019
00020
00021
00022 static const double A_SECOND = 1.0;
00023 static const double A_MINUTE = A_SECOND*60;
00024 static const double A_HOUR = A_MINUTE*60;
00025 static const double A_DAY = A_HOUR*24;
00026 static const double A_MONTH = A_DAY*30;
00027 static const double A_YEAR = A_MONTH*12;
00028
00029
00030
00034 SXYAxis::SXYAxis(SXYChart* cht, SXYAxisOrientation orient, SXYAxisType atype,
00035 double xpos, double ypos, double size) {
00036 orientation = orient;
00037 type = atype;
00038 chart = cht;
00039 precision = 0;
00040
00041 XYCartesian* graph = cht->getXyGraph();
00042 assert(graph);
00043
00044 int ref_font_size = SXYChart::getFontSizeReference();
00045 double angle;
00046
00047 if (orientation==HORIZONTAL_AXIS) {
00048 angle = 00.0;
00049 xy_decor_text = new XYMultiRasterText(XY_BLACK,
00050 ref_font_size, XYRasterText::helvetica, XYRasterText::plain,
00051 XYRasterText::north, XYRasterText::horizontal);
00052
00053 xy_label = new XYRasterText("x",
00054 XYCoordinate(0.5), XYCoordinate(ypos),
00055 XY_BLUE, ref_font_size+2, XYRasterText::helvetica,
00056 XYRasterText::plain, XYRasterText::center,
00057 XYRasterText::horizontal);
00058 }
00059 else {
00060 angle = 90.0;
00061 xy_decor_text = new XYMultiRasterText(XY_BLACK,
00062 ref_font_size, XYRasterText::helvetica, XYRasterText::plain,
00063 XYRasterText::south, XYRasterText::vertBotTop);
00064
00065 xy_label = new XYRasterText("y",
00066 XYCoordinate(xpos), XYCoordinate((double)0.5),
00067 XY_BLUE, ref_font_size+2, XYRasterText::helvetica,
00068 XYRasterText::plain, XYRasterText::center,
00069 XYRasterText::vertBotTop);
00070 }
00071
00072 assert(xy_decor_text);
00073 assert(xy_label);
00074
00075 buildDecoratorAxis(angle, xpos, ypos, size);
00076
00077 assert(xy_decor);
00078 assert(xy_axis);
00079
00080 title_style = AT_MIDDLE;
00081 scale_orientation = ALIGNED;
00082
00083 updateTitleStyle();
00084 updateScaleOrientation();
00085
00086 xy_axis->leftTick((orientation==HORIZONTAL_AXIS ? xyfalse : xytrue));
00087
00088
00089 graph->insert( xy_axis );
00090 tryScalesAdjust();
00091 graph->calcMaskArea();
00092 }
00093
00094
00095
00096 SXYAxisType SXYAxis::getType() {
00097 return type;
00098 }
00099
00100
00101
00102 void SXYAxis::setPrecision(int p) {
00103 if (p < 0) return;
00104 precision = p;
00105 }
00106
00107
00108
00109 int SXYAxis::getPixelValue( double position ) {
00110 int xp, yp;
00111 xy_axis->pointInValue(position,xp,yp);
00112 SXYAxisOrientation ori = getOrientation();
00113
00114 if (ori==HORIZONTAL_AXIS) return xp;
00115 if (ori==VERTICAL_AXIS) return yp;
00116
00117 assert(0);
00118 return -9999;
00119 }
00120
00121
00122
00123 double SXYAxis::getPositionValue( int pix ) {
00124 SXYAxisOrientation ori = getOrientation();
00125 int xp, yp;
00126
00127 if (ori==HORIZONTAL_AXIS) {
00128 xp = pix; yp = -999;
00129 return xy_axis->valueInPoint(xp,yp);
00130 }
00131 else if (ori==VERTICAL_AXIS) {
00132 xp = -999; yp = pix;
00133 return xy_axis->valueInPoint(xp,yp);
00134 }
00135
00136 assert(0);
00137 return FLT_MAX;
00138 }
00139
00140
00141
00142 SXYAxisOrientation SXYAxis::getOrientation() {
00143 return orientation;
00144 }
00145
00146
00147
00148 void SXYAxis::setColor(long int col) {
00149 xy_axis->color(col);
00150 }
00151
00152
00153
00154 void SXYAxis::buildDecoratorAxis(double angle, double xpos, double ypos,
00155 double size) {
00156 SXYAxisType type = getType();
00157
00158 if (type == LINEAR_AXIS) {
00159 xy_decor = new XYNumericalScaleDecorator("%.2f", xy_decor_text);
00160
00161 xy_axis = new XYLinearAxis(0, 10.0, xpos, ypos, XY_BLACK,
00162 size, angle, 1.0, xy_decor, xy_label, xytrue, xytrue);
00163
00164 xy_axis->min(0);
00165 xy_axis->max(100);
00166 xy_axis->step(10);
00167 }
00168 else if (type == LOG_AXIS) {
00169 xy_decor = new XYLogScaleDecorator("%.2f", xy_decor_text);
00170
00171 xy_axis = new XYLogAxis(0, 10.0, xpos, ypos, XY_BLACK,
00172 size, angle, 1.0, xy_decor, xy_label, xytrue, xytrue);
00173
00174 xy_axis->min(1);
00175 xy_axis->max(10);
00176 xy_axis->step(1);
00177 }
00178 else if (type == TIME_AXIS) {
00179 xy_decor = new XYDateScaleDecorator(xy_decor_text);
00180
00181 xy_axis = new XYLinearAxis(0, 10.0, xpos, ypos, XY_BLACK,
00182 size, angle, 1.0, xy_decor, xy_label, xytrue, xytrue);
00183
00184 xy_axis->min(0);
00185 xy_axis->max(A_DAY);
00186 xy_axis->step(A_HOUR);
00187 }
00188 else {
00189 assert(0);
00190 }
00191 }
00192
00193
00194
00195 void SXYAxis::updateScaleOrientation(void) {
00196 if (orientation == HORIZONTAL_AXIS) {
00197 if (scale_orientation == ALIGNED) {
00198 xy_decor_text->orientation( XYText::horizontal );
00199 xy_decor_text->align( XYText::north );
00200 }
00201 else {
00202 xy_decor_text->orientation( XYText::vertBotTop );
00203 xy_decor_text->align( XYText::east );
00204 }
00205 }
00206 else {
00207 if (scale_orientation == ALIGNED) {
00208 xy_decor_text->orientation( XYText::vertBotTop );
00209 xy_decor_text->align( XYText::south );
00210 }
00211 else {
00212 xy_decor_text->orientation( XYText::horizontal );
00213 xy_decor_text->align( XYText::east );
00214 }
00215 }
00216 }
00217
00218
00219
00220 void SXYAxis::updateTitleStyle(void) {
00221 double aposx, aposy;
00222 if (xy_axis == NULL) return;
00223 xy_axis->position(&aposx, &aposy);
00224 double as = xy_axis->size();
00225
00226 if (orientation == HORIZONTAL_AXIS) {
00227 if (title_style == AT_MIDDLE) {
00228 xy_label->position( aposx + as/2, aposy*2/3 );
00229 xy_label->align( XYText::north );
00230 xy_label->orientation( XYText::horizontal );
00231 }
00232 else if (title_style == AT_END) {
00233 xy_label->position( aposx+as+aposx/3, aposy );
00234 xy_label->align( XYText::west );
00235 xy_label->orientation( XYText::horizontal );
00236 }
00237 else if (title_style == AT_END_ROTATED) {
00238 xy_label->position( aposx+as+aposx/2, aposy );
00239 xy_label->align( XYText::west );
00240 xy_label->orientation( XYText::vertBotTop );
00241 }
00242 }
00243 else {
00244 if (title_style == AT_MIDDLE) {
00245 xy_label->position( aposx*2/3, aposy + as/2 );
00246 xy_label->align( XYText::south );
00247 xy_label->orientation( XYText::vertBotTop );
00248 }
00249 else if (title_style == AT_END) {
00250 xy_label->position( aposx, aposy+as+aposy/3 );
00251 xy_label->align( XYText::west );
00252 xy_label->orientation( XYText::vertBotTop );
00253 }
00254 else if (title_style == AT_END_ROTATED) {
00255 xy_label->position( aposx, aposy+as+aposy/2 );
00256 xy_label->align( XYText::west );
00257 xy_label->orientation( XYText::horizontal );
00258 }
00259 }
00260 }
00261
00262
00263
00264 void SXYAxis::setScaleOrientation(SXYAxisScaleOrientation ori) {
00265 scale_orientation = ori;
00266 updateScaleOrientation();
00267 }
00268
00269
00270
00271 SXYAxisScaleOrientation SXYAxis::getScaleOrientation(void) {
00272 return scale_orientation;
00273 }
00274
00275
00276
00277 void SXYAxis::setDirection(SXYAxisDirection direction) {
00278 assert(xy_axis!=NULL);
00279 double ang = 45.0;
00280 if (orientation == HORIZONTAL_AXIS) {
00281 if (direction == NORMAL_AXIS) {
00282 ang = 0.0;
00283 xy_axis->leftTick(xyfalse);
00284 }
00285 else {
00286 ang = 180.0;
00287 xy_axis->leftTick(xyfalse);
00288 }
00289 }
00290 else {
00291 if (direction == NORMAL_AXIS) {
00292 xy_axis->leftTick(xytrue);
00293 ang = 90.0;
00294 }
00295 else {
00296 ang = 270.0;
00297 xy_axis->leftTick(xytrue);
00298 }
00299 }
00300 xy_axis->rotation(ang);
00301 updateScaleOrientation();
00302 }
00303
00304
00305
00306 SXYAxisDirection SXYAxis::getDirection(void) {
00307 assert(xy_axis!=NULL);
00308 if (orientation == HORIZONTAL_AXIS) {
00309 double ang = xy_axis->rotation();
00310 return ang == 0.0 ? NORMAL_AXIS : INVERTED_AXIS;
00311 }
00312 else {
00313 double ang = xy_axis->rotation();
00314 return ang == 90.0 ? NORMAL_AXIS : INVERTED_AXIS;
00315 }
00316 }
00317
00318
00319
00320 void SXYAxis::setTitleStyle(SXYAxisTitleStyle sty) {
00321 title_style = sty;
00322 updateTitleStyle();
00323 }
00324
00325
00326
00327 SXYAxisTitleStyle SXYAxis::getTitleStyle(void) {
00328 return title_style;
00329 }
00330
00331
00332
00333 long int SXYAxis::getColor(void) {
00334 return xy_axis->color();
00335 }
00336
00337
00338
00339 void SXYAxis::setTitleColor(long int col) {
00340 xy_label->color(col);
00341 }
00342
00343
00344
00345 long int SXYAxis::getTitleColor(void) {
00346 return xy_label->color();
00347 }
00348
00349
00350
00351 void SXYAxis::setScaleColor(long int col) {
00352 xy_decor_text->color(col);
00353 }
00354
00355
00356
00357 long int SXYAxis::getScaleColor(void) {
00358 return xy_decor_text->color();
00359 }
00360
00361
00362
00363 void SXYAxis::setPosition(double posx, double posy) {
00364 xy_axis->position( posx, posy );
00365 updateTitleStyle();
00366 updateScaleOrientation();
00367 }
00368
00369
00370
00371 void SXYAxis::getPosition(double& posx, double& posy) {
00372 double px, py;
00373 xy_axis->position(&px, &py);
00374 posx = px;
00375 posy = py;
00376 }
00377
00378
00379
00380 void SXYAxis::setArrowVisibility(int vis) {
00381 xy_axis->arrow(vis == 1 ? xytrue : xyfalse);
00382 }
00383
00384
00385
00386 int SXYAxis::getArrowVisibility(void) {
00387 return xy_axis->arrow() == xytrue ? 1 : 0;
00388 }
00389
00390
00391
00392
00393 void SXYAxis::setSize(double siz) {
00394 xy_axis->size(siz);
00395 }
00396
00397
00398
00399 double SXYAxis::getSize(void) {
00400 return xy_axis->size();
00401 }
00402
00403
00404
00406 SXYAxis::~SXYAxis() {
00407 delete xy_decor_text;
00408 xy_decor_text = NULL;
00409
00410 delete xy_decor;
00411 xy_decor = NULL;
00412
00413 delete xy_label;
00414 xy_label = NULL;
00415
00416 delete xy_axis;
00417 xy_axis = NULL;
00418 }
00419
00420
00421
00422 void SXYAxis::setTitle(char* txt) {
00423 xy_label->text( (const char*)txt );
00424 }
00425
00426
00427
00428 char* SXYAxis::getTitle(void) {
00429 return xy_label->text();
00430 }
00431
00432
00433
00434 void SXYAxis::getScales(double& minimum, double& maximum) {
00435 assert(xy_axis != NULL);
00436
00437
00438 minimum = xy_axis->min();
00439 maximum = xy_axis->max();
00440 }
00441
00442
00443
00444 void SXYAxis::setZoom(double ratio) {
00445 double vmin, vmax;
00446 getScales(vmin, vmax);
00447
00448 if ( getType() == LOG_AXIS ) {
00449 double va = log10(vmin);
00450 double vb = log10(vmax);
00451 double dv = ( vb - va ) * -ratio;
00452 va = va - dv;
00453 vb = vb + dv;
00454 vmin = pow( 10, va );
00455 vmax = pow( 10, vb );
00456 if (vmin < 1) setScales(1, vmax);
00457 else setScales(vmin, vmax);
00458 }
00459 else {
00460 double dv = (vmax - vmin) * -ratio;
00461 setScales(vmin-dv, vmax+dv);
00462 }
00463 }
00464
00465
00466
00467 void SXYAxis::calcPrecision() {
00468 SXYAxisType type = getType();
00469 if (type == LOG_AXIS) {
00470 setFormat("%.0f");
00471 }
00472 else if (type == LINEAR_AXIS){
00473 double min, max;
00474 getScales(min, max);
00475 char prec[30];
00476 int precision = SXYUtil::calcPrecision(min, max);
00477 sprintf(prec, "%%.%df", precision);
00478 setFormat(prec);
00479 }
00480 }
00481
00482
00483
00484 double SXYAxis::getStep(void) {
00485 assert(xy_axis != NULL);
00486 return xy_axis->step();
00487 }
00488
00489
00490
00491 void SXYAxis::tryStepAdjust(void) {
00492 SXYAxisType type = getType();
00493 if (type == LOG_AXIS) {
00494 setStep(1.0);
00495 }
00496 else if (type == LINEAR_AXIS) {
00497 double vmin, vmax;
00498 getScales(vmin, vmax);
00499 double dv = fabs(vmax - vmin) / 10;
00500 setStep(dv);
00501 }
00502 else if (type == TIME_AXIS) {
00503 double vmin, vmax;
00504 getScales(vmin, vmax);
00505 double dv = fabs(vmax - vmin);
00506 if (dv >= A_YEAR) dv = A_MONTH;
00507 else if (dv >= A_MONTH) dv = A_DAY;
00508 else if (dv >= A_DAY) dv = A_HOUR;
00509 else if (dv >= A_HOUR) dv = A_MINUTE;
00510 else dv = dv/6;
00511 setStep(dv);
00512 }
00513 }
00514
00515
00516
00517 void SXYAxis::tryScalesAdjust(void) {
00518 SXYAxisType type = getType();
00519 if (type == LOG_AXIS) {
00520 double vmin, vmax;
00521 getScales(vmin, vmax);
00522 int imin = (int)floor(log10(vmin));
00523 int imax = (int)ceil(log10(vmax));
00524 if (imin == imax) imax = imin +1;
00525 vmin = pow(10, imin);
00526 vmax = pow(10, imax);
00527 setScales(vmin, vmax);
00528 }
00529 else if (type == LINEAR_AXIS) {
00530 double vmin, vmax;
00531 getScales(vmin, vmax);
00532 double dv = (vmax - vmin) / 10;
00533 if (dv > 1) {
00534 vmin = floor(vmin);
00535 vmax = ceil(vmax);
00536 }
00537 setScales(vmin, vmax);
00538 }
00539 else if (type == TIME_AXIS) {
00540 double vmin, vmax;
00541 getScales(vmin, vmax);
00542 double dv = (vmax - vmin);
00543 if (dv < A_HOUR) {
00544 vmin = floor(vmin/A_MINUTE)*A_MINUTE;
00545 vmax = ceil(vmax/A_MINUTE)*A_MINUTE;
00546 }
00547 else if (dv < A_DAY) {
00548 vmin = floor(vmin/A_HOUR)*A_HOUR;
00549 vmax = ceil(vmax/A_HOUR)*A_HOUR;
00550 }
00551 else {
00552 vmin = floor(vmin/A_DAY)*A_DAY;
00553 vmax = ceil(vmax/A_DAY)*A_DAY;
00554 }
00555 setScales(vmin, vmax);
00556 }
00557
00558 tryStepAdjust();
00559 if (precision == 0) {
00560 calcPrecision();
00561 }
00562 else {
00563 SXYAxisType type = getType();
00564 if (type == LOG_AXIS) {
00565 setFormat("%.0f");
00566 }
00567 else if (type == LINEAR_AXIS) {
00568 char prec[30];
00569 sprintf(prec, "%%.%df", precision);
00570 setFormat(prec);
00571 }
00572 }
00573 }
00574
00575
00576
00577 void SXYAxis::setVisibility(int flag) {
00578 assert(xy_axis);
00579 xy_axis->visible(flag ? xytrue : xyfalse);
00580 }
00581
00582
00583
00584 int SXYAxis::getVisibility(void) {
00585 assert(xy_axis);
00586 return xy_axis->visible() == xytrue ? 1 : 0;
00587 }
00588
00589
00590
00591 void SXYAxis::setFormat(char* fmt) {
00592 assert(xy_decor);
00593 if (type == LINEAR_AXIS) {
00594 ((XYNumericalScaleDecorator*)xy_decor)->format(fmt);
00595 }
00596 else if (type == LOG_AXIS) {
00597 ((XYLogScaleDecorator*)xy_decor)->format(fmt);
00598 }
00599 else {
00600 assert(type != TIME_AXIS);
00601 assert(0);
00602 }
00603 }
00604
00605
00606
00607 char* SXYAxis::getFormat(void) {
00608 assert(xy_decor);
00609 if (type == LINEAR_AXIS)
00610 return ((XYNumericalScaleDecorator*)xy_decor)->format();
00611 else
00612 return ((XYLogScaleDecorator*)xy_decor)->format();
00613
00614 assert(0);
00615 return NULL;
00616 }
00617
00618
00619
00620
00621 void SXYAxis::setScales(double minimum, double maximum) {
00622 assert(xy_axis != NULL);
00623 assert(minimum < maximum);
00624 if (type == LOG_AXIS && minimum < 1e-15) minimum = 1;
00625
00626
00627
00628
00629 xy_axis->min(minimum);
00630 xy_axis->max(maximum);
00631 }
00632
00633
00634
00635 void SXYAxis::setStep(double step) {
00636 assert(xy_axis != NULL);
00637 xy_axis->step( fabs(step) );
00638 }
00639
00640
00641
00642 XYRasterText* SXYAxis::getXyDecorator(void) {
00643 return xy_decor_text;
00644 }
00645
00646
00647
00648 XYRasterText* SXYAxis::getXyTitle(void) {
00649 return xy_label;
00650 }
00651
00652
00653
00654 XYAxis* SXYAxis::getXyAxis(void) {
00655 return xy_axis;
00656 }
00657
00658
00659
00660 void SXYAxis::setLayoutFrom(SXYAxis* other) {
00661 setTitle( other->getTitle() );
00662 setVisibility( other->getVisibility() );
00663 setArrowVisibility( other->getArrowVisibility() );
00664 setTitleStyle( other->getTitleStyle() );
00665 setScaleOrientation( other->getScaleOrientation() );
00666
00667 setSize( other->getSize() );
00668
00669 double posx, posy;
00670 other->getPosition(posx, posy);
00671 setPosition(posx, posy);
00672 setDirection(other->getDirection());
00673
00674 setColor( other->getColor() );
00675 setScaleColor( other->getScaleColor() );
00676 setTitleColor( other->getTitleColor() );
00677 }
00678
00679
00680
00681 SXYChart* SXYAxis::getChart(void) {
00682 return chart;
00683 }
00684
00685
00686
00687
00688
00689