2 * fill-series.c: Fill according to a linear or exponential serie.
5 * Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
6 * Andreas J. Guelzow <aguelzow@taliesin.ca>
8 * (C) Copyright 2003 by Jukka-Pekka Iivonen <jiivonen@hutcs.cs.hut.fi>
9 * (C) Copyright 2003 by Andreas J. Guelzow <aguelzow@taliesin.ca>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses/>.
25 #include <gnumeric-config.h>
26 #include <glib/gi18n-lib.h>
30 #include <sheet-filter.h>
34 #include <gnm-format.h>
36 #include <tools/tools.h>
38 #include <gnm-datetime.h>
41 #include <tools/fill-series.h>
42 #include <goffice/goffice.h>
45 do_row_filling_wday (data_analysis_output_t
*dao
, fill_series_t
*info
)
48 gnm_float start
= info
->start_value
;
50 GODateConventions
const *conv
=
51 sheet_date_conv (dao
->sheet
);
54 for (i
= 0; i
< info
->n
; i
++) {
55 int steps
= (i
* info
->step_value
) + 0.5;
56 int days
= (steps
/ 5) * 7 + steps
% 5;
59 go_date_serial_to_g (&date
, start
, conv
);
60 wd
= g_date_get_weekday (&date
);
61 if (wd
+ (steps
% 5) > G_DATE_FRIDAY
)
63 gnm_date_add_days (&date
, days
);
65 dao_set_cell_float (dao
, i
, 0,
66 go_date_g_to_serial (&date
, conv
));
72 do_column_filling_wday (data_analysis_output_t
*dao
, fill_series_t
*info
)
75 gnm_float start
= info
->start_value
;
77 GODateConventions
const *conv
=
78 sheet_date_conv (dao
->sheet
);
81 for (i
= 0; i
< info
->n
; i
++) {
82 int steps
= (i
* info
->step_value
) + 0.5;
83 int days
= (steps
/ 5) * 7 + steps
% 5;
86 go_date_serial_to_g (&date
, start
, conv
);
87 wd
= g_date_get_weekday (&date
);
88 if (wd
+ (steps
% 5) > G_DATE_FRIDAY
)
90 gnm_date_add_days (&date
, days
);
92 dao_set_cell_float (dao
, 0,i
,
93 go_date_g_to_serial (&date
, conv
));
100 do_row_filling_month (data_analysis_output_t
*dao
, fill_series_t
*info
)
103 gnm_float start
= info
->start_value
;
105 GODateConventions
const *conv
=
106 sheet_date_conv (dao
->sheet
);
109 for (i
= 0; i
< info
->n
; i
++) {
110 go_date_serial_to_g (&date
, start
, conv
);
111 gnm_date_add_months (&date
, i
* info
->step_value
);
113 dao_set_cell_float (dao
, i
, 0,
114 go_date_g_to_serial (&date
, conv
));
119 do_column_filling_month (data_analysis_output_t
*dao
, fill_series_t
*info
)
122 gnm_float start
= info
->start_value
;
124 GODateConventions
const *conv
=
125 sheet_date_conv (dao
->sheet
);
128 for (i
= 0; i
< info
->n
; i
++) {
129 go_date_serial_to_g (&date
, start
, conv
);
130 gnm_date_add_months (&date
, i
* info
->step_value
);
132 dao_set_cell_float (dao
, 0, i
,
133 go_date_g_to_serial (&date
, conv
));
138 do_row_filling_year (data_analysis_output_t
*dao
, fill_series_t
*info
)
141 gnm_float start
= info
->start_value
;
143 GODateConventions
const *conv
=
144 sheet_date_conv (dao
->sheet
);
147 for (i
= 0; i
< info
->n
; i
++) {
148 go_date_serial_to_g (&date
, start
, conv
);
149 gnm_date_add_years (&date
, i
* info
->step_value
);
151 dao_set_cell_float (dao
, i
, 0,
152 go_date_g_to_serial (&date
, conv
));
157 do_column_filling_year (data_analysis_output_t
*dao
, fill_series_t
*info
)
160 gnm_float start
= info
->start_value
;
162 GODateConventions
const *conv
=
163 sheet_date_conv (dao
->sheet
);
166 for (i
= 0; i
< info
->n
; i
++) {
167 go_date_serial_to_g (&date
, start
, conv
);
168 gnm_date_add_years (&date
, i
* info
->step_value
);
170 dao_set_cell_float (dao
, 0, i
,
171 go_date_g_to_serial (&date
, conv
));
176 do_row_filling_linear (data_analysis_output_t
*dao
, fill_series_t
*info
)
179 gnm_float start
= info
->start_value
;
180 gnm_float step
= info
->step_value
;
182 for (i
= 0; i
< info
->n
; i
++) {
183 dao_set_cell_float (dao
, i
, 0, start
);
189 do_column_filling_linear (data_analysis_output_t
*dao
, fill_series_t
*info
)
192 gnm_float start
= info
->start_value
;
193 gnm_float step
= info
->step_value
;
195 for (i
= 0; i
< info
->n
; i
++) {
196 dao_set_cell_float (dao
, 0, i
, start
);
202 do_row_filling_growth (data_analysis_output_t
*dao
, fill_series_t
*info
)
205 gnm_float start
= info
->start_value
;
206 gnm_float step
= info
->step_value
;
208 for (i
= 0; i
< info
->n
; i
++) {
209 dao_set_cell_float (dao
, i
, 0, start
);
215 do_column_filling_growth (data_analysis_output_t
*dao
, fill_series_t
*info
)
218 gnm_float start
= info
->start_value
;
219 gnm_float step
= info
->step_value
;
221 for (i
= 0; i
< info
->n
; i
++) {
222 dao_set_cell_float (dao
, 0, i
, start
);
228 fill_series_adjust_variables (data_analysis_output_t
*dao
, fill_series_t
*info
)
230 int length_of_series
= -1;
231 int length_of_space
= info
->series_in_rows
232 ? dao
->cols
: dao
->rows
;
234 if (info
->type
== FillSeriesTypeDate
&&
235 info
->date_unit
!= FillSeriesUnitDay
) {
236 if (info
->is_step_set
)
237 info
->step_value
= gnm_floor (info
->step_value
+ 0.5);
239 info
->step_value
= 1;
240 if (info
->is_stop_set
) {
241 GDate from_date
, to_date
;
242 GODateConventions
const *conv
=
243 sheet_date_conv (dao
->sheet
);
245 if (info
->step_value
< 0) {
246 go_date_serial_to_g (&from_date
,
247 info
->stop_value
, conv
);
248 go_date_serial_to_g (&to_date
,
249 info
->start_value
, conv
);
251 go_date_serial_to_g (&from_date
,
252 info
->start_value
, conv
);
253 go_date_serial_to_g (&to_date
,
254 info
->stop_value
, conv
);
256 switch (info
->date_unit
) {
257 case FillSeriesUnitDay
:
258 /* This should not happen*/
260 case FillSeriesUnitWeekday
:
263 days
= g_date_days_between
264 (&from_date
, &to_date
);
265 length_of_series
= (days
/ 7) * 5 + 1
267 if (length_of_series
< 1)
268 length_of_series
= 1;
271 case FillSeriesUnitMonth
:
273 GDateYear from_year
, to_year
;
274 GDateMonth from_month
, to_month
;
277 from_year
= g_date_get_year(&from_date
);
278 to_year
= g_date_get_year(&to_date
);
279 from_month
= g_date_get_month(&from_date
);
280 to_month
= g_date_get_month(&to_date
);
281 g_date_set_year (&to_date
, from_year
);
283 if (g_date_compare (&from_date
, &to_date
) > 0)
284 months
= (to_year
- from_year
) * 12 +
285 (to_month
- from_month
);
287 months
= (to_year
- from_year
) * 12 +
288 (to_month
- from_month
) + 1;
289 length_of_series
= months
290 / (int)(info
->step_value
+ 0.5);
291 if (length_of_series
< 1)
292 length_of_series
= 1;
295 case FillSeriesUnitYear
:
297 GDateYear from_year
, to_year
;
300 from_year
= g_date_get_year(&from_date
);
301 to_year
= g_date_get_year(&to_date
);
302 g_date_set_year (&to_date
, from_year
);
303 if (g_date_compare (&from_date
, &to_date
) > 0)
304 years
= to_year
- from_year
;
306 years
= to_year
- from_year
+ 1;
307 length_of_series
= years
308 / (int)(info
->step_value
+ 0.5);
309 if (length_of_series
< 1)
310 length_of_series
= 1;
317 if (!info
->is_step_set
) {
318 switch (info
->type
) {
319 case FillSeriesTypeDate
:
320 case FillSeriesTypeLinear
:
322 (info
->stop_value
- info
->start_value
)/
323 (length_of_space
- 1);
325 case FillSeriesTypeGrowth
:
327 gnm_exp((gnm_log(info
->stop_value
328 /info
->start_value
))/
329 (length_of_space
- 1));
332 info
->is_step_set
= TRUE
;
333 } else if (info
->is_stop_set
) {
334 switch (info
->type
) {
335 case FillSeriesTypeDate
:
336 case FillSeriesTypeLinear
:
338 = gnm_floor(GNM_EPSILON
+ 1 +
340 - info
->start_value
)/
342 if (length_of_series
< 1)
343 length_of_series
= 1;
345 case FillSeriesTypeGrowth
:
347 = gnm_floor(GNM_EPSILON
+ 1 +
348 (gnm_log(info
->stop_value
349 /info
->start_value
))/
350 gnm_log(info
->step_value
));
351 if (length_of_series
< 1)
352 length_of_series
= 1;
357 if (info
->series_in_rows
) {
358 dao_adjust (dao
, length_of_series
, 1);
361 dao_adjust (dao
, 1, length_of_series
);
364 if (length_of_series
> 0)
365 info
->n
= length_of_series
;
368 gboolean
fill_series_engine (G_GNUC_UNUSED GOCmdContext
*gcc
, data_analysis_output_t
*dao
, gpointer specs
,
369 analysis_tool_engine_t selector
, gpointer result
)
371 fill_series_t
*info
= specs
;
374 case TOOL_ENGINE_UPDATE_DESCRIPTOR
:
375 return (dao_command_descriptor (dao
, _("Fill Series (%s)"),
377 case TOOL_ENGINE_UPDATE_DAO
:
378 fill_series_adjust_variables (dao
, info
);
380 case TOOL_ENGINE_CLEAN_UP
:
382 case TOOL_ENGINE_LAST_VALIDITY_CHECK
:
384 case TOOL_ENGINE_PREPARE_OUTPUT_RANGE
:
385 dao_prepare_output (NULL
, dao
, _("Fill Series"));
387 case TOOL_ENGINE_FORMAT_OUTPUT_RANGE
:
388 return dao_format_output (dao
, _("Fill Series"));
389 case TOOL_ENGINE_PERFORM_CALC
:
391 switch (info
->type
) {
392 case FillSeriesTypeLinear
:
393 if (info
->series_in_rows
)
394 do_row_filling_linear (dao
, info
);
396 do_column_filling_linear (dao
, info
);
398 case FillSeriesTypeGrowth
:
399 if (info
->series_in_rows
)
400 do_row_filling_growth (dao
, info
);
402 do_column_filling_growth (dao
, info
);
404 case FillSeriesTypeDate
:
405 switch (info
->date_unit
) {
406 case FillSeriesUnitDay
:
407 if (info
->series_in_rows
)
408 do_row_filling_linear (dao
, info
);
410 do_column_filling_linear (dao
, info
);
412 case FillSeriesUnitWeekday
:
413 if (info
->series_in_rows
)
414 do_row_filling_wday (dao
, info
);
416 do_column_filling_wday (dao
, info
);
418 case FillSeriesUnitMonth
:
419 if (info
->series_in_rows
)
420 do_row_filling_month (dao
, info
);
422 do_column_filling_month (dao
, info
);
424 case FillSeriesUnitYear
:
425 if (info
->series_in_rows
)
426 do_row_filling_year (dao
, info
);
428 do_column_filling_year (dao
, info
);
431 dao_set_date (dao
, 0, 0,
432 dao
->cols
- 1, dao
->rows
-1);
437 return TRUE
; /* We shouldn't get here */