src/graph_gui.cpp
changeset 8000 2ba28bc428f1
parent 7997 df87ccd00a96
child 8106 e6790dd9e750
equal deleted inserted replaced
7999:bb3a1508fd71 8000:2ba28bc428f1
    63 
    63 
    64 	int left, top;  ///< Where to start drawing the graph, in pixels.
    64 	int left, top;  ///< Where to start drawing the graph, in pixels.
    65 	uint height;    ///< The height of the graph in pixels.
    65 	uint height;    ///< The height of the graph in pixels.
    66 	StringID format_str_y_axis;
    66 	StringID format_str_y_axis;
    67 	byte colors[GRAPH_MAX_DATASETS];
    67 	byte colors[GRAPH_MAX_DATASETS];
    68 	Money cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
    68 	OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
    69 };
    69 };
    70 
    70 
    71 static void DrawGraph(const GraphDrawer *gw)
    71 static void DrawGraph(const GraphDrawer *gw)
    72 {
    72 {
    73 	uint x, y;                       ///< Reused whenever x and y coordinates are needed.
    73 	uint x, y;                       ///< Reused whenever x and y coordinates are needed.
   131 	highest_value = x_axis_offset * 2;
   131 	highest_value = x_axis_offset * 2;
   132 
   132 
   133 	for (int i = 0; i < gw->num_dataset; i++) {
   133 	for (int i = 0; i < gw->num_dataset; i++) {
   134 		if (!HasBit(gw->excluded_data, i)) {
   134 		if (!HasBit(gw->excluded_data, i)) {
   135 			for (int j = 0; j < gw->num_on_x_axis; j++) {
   135 			for (int j = 0; j < gw->num_on_x_axis; j++) {
   136 				Money datapoint = gw->cost[i][j];
   136 				OverflowSafeInt64 datapoint = gw->cost[i][j];
   137 
   137 
   138 				if (datapoint != INVALID_DATAPOINT) {
   138 				if (datapoint != INVALID_DATAPOINT) {
   139 					/* For now, if the graph has negative values the scaling is
   139 					/* For now, if the graph has negative values the scaling is
   140 					 * symmetrical about the x axis, so take the absolute value
   140 					 * symmetrical about the x axis, so take the absolute value
   141 					 * of each data point. */
   141 					 * of each data point. */
   213 			byte color  = gw->colors[i];
   213 			byte color  = gw->colors[i];
   214 			uint prev_x = INVALID_DATAPOINT_POS;
   214 			uint prev_x = INVALID_DATAPOINT_POS;
   215 			uint prev_y = INVALID_DATAPOINT_POS;
   215 			uint prev_y = INVALID_DATAPOINT_POS;
   216 
   216 
   217 			for (int j = 0; j < gw->num_on_x_axis; j++) {
   217 			for (int j = 0; j < gw->num_on_x_axis; j++) {
   218 				Money datapoint = gw->cost[i][j];
   218 				OverflowSafeInt64 datapoint = gw->cost[i][j];
   219 
   219 
   220 				if (datapoint != INVALID_DATAPOINT) {
   220 				if (datapoint != INVALID_DATAPOINT) {
   221 					/* XXX: This can overflow if x_axis_offset * datapoint is
   221 					/*
   222 					 * too big to fit in an int64. */
   222 					 * Check whether we need to reduce the 'accuracy' of the
   223 					y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / highest_value;
   223 					 * datapoint value and the highest value to splut overflows.
       
   224 					 * And when 'drawing' 'one million' or 'one million and one'
       
   225 					 * there is no significant difference, so the least
       
   226 					 * significant bits can just be removed.
       
   227 					 *
       
   228 					 * If there are more bits needed than would fit in a 32 bits
       
   229 					 * integer, so at about 31 bits because of the sign bit, the
       
   230 					 * least significant bits are removed.
       
   231 					 */
       
   232 					int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
       
   233 					int reduce_range = max(mult_range - 31, 0);
       
   234 
       
   235 					/* Handle negative values differently (don't shift sign) */
       
   236 					if (datapoint < 0) {
       
   237 						datapoint = -(abs(datapoint) >> reduce_range);
       
   238 					} else {
       
   239 						datapoint >>= reduce_range;
       
   240 					}
       
   241 
       
   242 					y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
   224 
   243 
   225 					/* Draw the point. */
   244 					/* Draw the point. */
   226 					GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
   245 					GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
   227 
   246 
   228 					/* Draw the line connected to the previous point. */
   247 					/* Draw the line connected to the previous point. */