Files
herolib/lib/biz/spreadsheet/extrapolate.v
2024-12-30 12:22:36 +02:00

117 lines
3.7 KiB
V

module spreadsheet
import freeflowuniverse.herolib.ui.console
// smartstring is something like 3:2,10:5 means end month 3 we start with 2, it grows to 5 on end month 10 .
// the cells out of the mentioned ranges are not filled if they are already set .
// the cells which are empty at start of row will become 0 .
// the cells which are empty at the back will just be same value as the last one .
// currencies can be used e.g. 3:10usd,20:30aed (so we can even mix) .
// first cell is 1, the start is 0 (month 0) .
// if the smartstr, is empty then will use existing values in the row to extra/intra polate, the empty values will be filled in
pub fn (mut r Row) extrapolate(smartstr string) ! {
// put the values in the row
// console.print_debug("extrapolate: ${smartstr}")
for mut part in smartstr.split(',') {
part = part.trim_space()
if part.contains(':') {
splitted := part.split(':')
if splitted.len != 2 {
return error("smartextrapolate needs '3:2,10:5' as format, now ${smartstr} ")
}
mut x := splitted[0].int()
if x < 0 {
return error('Cannot do smartstr, because the X is out of scope.\n${smartstr}')
}
if x > r.sheet.nrcol - 1 {
x = r.sheet.nrcol - 1
}
r.cells[x].set(splitted[1])!
}
}
mut xlast := 0 // remembers where there was last non empty value
mut has_previous_value := false
mut xlastval := 0.0 // the value at that position
mut xlastwidth := 0 // need to know how fast to go up from the xlast to xnew
mut xnewval := 0.0
// console.print_debug(r)
for x in 0 .. r.cells.len {
// console.print_debug("$x empty:${r.cells[x].empty} xlastwidth:$xlastwidth xlastval:$xlastval xlast:$xlast")
if r.cells[x].empty && !has_previous_value {
continue
}
has_previous_value = true
if r.cells[x].empty == false && xlastwidth == 0 {
// we get new value, just go to next
xlast = x
xlastval = r.cells[x].val
xlastwidth = 0
// console.print_debug(" lastval:$xlastval")
continue // no need to do anything
}
// if we get here we get an empty after having a non empty before
xlastwidth += 1
if r.cells[x].empty == false {
// now we find the next one not being empty so we need to do the interpolation
xnewval = r.cells[x].val
// now we need to walk over the inbetween and set the values
yincr := (xnewval - xlastval) / xlastwidth
mut yy := xlastval
// console.print_debug(" yincr:$yincr")
for xx in (xlast + 1) .. x {
yy += yincr
r.cells[xx].set('${yy:.2f}')!
}
xlast = x
xlastval = xnewval
xlastwidth = 0
xnewval = 0.0
}
}
// console.print_debug("ROW1:$r")
// now fill in the last ones
xlastval = 0.0
for x in 0 .. r.cells.len {
if r.cells[x].empty == false {
xlastval = r.cells[x].val
continue
}
r.cells[x].set('${xlastval:.2f}')!
}
// console.print_debug("ROW:$r")
// if true{panic("s")}
}
// something like 3:2,10:5 means end month 3 we set 2, month 10 5
// there i no interpolation, all other fields are set on 0
pub fn (mut r Row) smartfill(smartstr string) ! {
// console.print_debug("smartfill: ${smartstr}")
for mut part in smartstr.split(',') {
part = part.trim_space()
if part.contains(':') {
splitted := part.split(':')
if splitted.len != 2 {
return error("smartextrapolate needs '3:2,10:5' as format, now ${smartstr} ")
}
x := splitted[0].int()
if x < 0 {
return error('Cannot do smartstr, because the X is out of scope.\n${smartstr}')
}
if x > r.sheet.nrcol {
return error('Cannot do smartstr, because the X is out of scope, needs to be 1+.\n${smartstr}')
}
r.cells[x].set(splitted[1])!
} else {
r.cells[0].set(part)!
}
}
for x in 0 .. r.cells.len {
if r.cells[x].empty {
r.cells[x].set('0.0')!
}
}
}