diff options
author | Sebastian Geerken <devnull@localhost> | 2014-06-29 19:43:10 +0200 |
---|---|---|
committer | Sebastian Geerken <devnull@localhost> | 2014-06-29 19:43:10 +0200 |
commit | 6e5e014abae063bd2f67323a0f001d41c8f1b424 (patch) | |
tree | 2135f5084dd224f6cdf13d35dee3bdb5c5ee9ea6 | |
parent | 60c5aa4e4843de237f9102a385efaa81b61c7ea0 (diff) |
Tables: reorganisation, part 3 (finish for now).
-rw-r--r-- | dw/table.cc | 148 | ||||
-rw-r--r-- | dw/table.hh | 2 |
2 files changed, 113 insertions, 37 deletions
diff --git a/dw/table.cc b/dw/table.cc index 1334323f..061acef8 100644 --- a/dw/table.cc +++ b/dw/table.cc @@ -1013,54 +1013,130 @@ void Table::calcExtremesSpanMulteCols (int col, int cs, /** * \brief Actual apportionment function. */ -void Table::apportion2 (int width, int firstCol, int lastCol, +void Table::apportion2 (int totalWidth, int firstCol, int lastCol, ExtrMod minExtrMod, ExtrMod maxExtrMod, misc::SimpleVector<int> *dest, int destOffset) { DBG_OBJ_MSGF ("resize", 0, "<b>apportion2</b> (%d, %d, %d, %s, %s, ..., %d)", - width, firstCol, lastCol, getExtrModName (minExtrMod), + totalWidth, firstCol, lastCol, getExtrModName (minExtrMod), getExtrModName (maxExtrMod), destOffset); DBG_OBJ_MSG_START (); if (lastCol >= firstCol) { - int minWidth = 0, maxWidth = 0; - - for (int col = firstCol; col <= lastCol; col++) { - minWidth += getColExtreme (col, minExtrMod); - maxWidth += getColExtreme (col, maxExtrMod); - } - dest->setSize (destOffset + lastCol - firstCol + 1, 0); - - DBG_OBJ_MSGF ("resize", 1, "width = %d, minWidth = %d, maxWidth = %d", - width, minWidth, maxWidth); - - // General case. - int curTargetWidth = misc::max (width, minWidth); - int curExtraWidth = curTargetWidth - minWidth; - int curMaxWidth = maxWidth; - int curNewWidth = minWidth; + int totalMin = 0, totalMax = 0; for (int col = firstCol; col <= lastCol; col++) { - int colMinWidth = getColExtreme (col, minExtrMod); - int colMaxWidth = getColExtreme (col, maxExtrMod); - int w = (curMaxWidth <= 0) ? 0 : - (int)((float)curTargetWidth * colMaxWidth/curMaxWidth); - - if (w <= colMinWidth) - w = colMinWidth; - else if (curNewWidth - colMinWidth + w > curTargetWidth) - w = colMinWidth + curExtraWidth; - - _MSG("w = %d\n", w); - - curNewWidth -= colMinWidth; - curMaxWidth -= colMaxWidth; - curExtraWidth -= (w - colMinWidth); - curTargetWidth -= w; - - dest->set (destOffset - firstCol + col, w); + totalMin += getColExtreme (col, minExtrMod); + totalMax += getColExtreme (col, maxExtrMod); + } + + DBG_OBJ_MSGF ("resize", 1, + "totalWidth = %d, totalMin = %d, totalMax = %d", + totalWidth, totalMin, totalMax); + + // The following line must be removed soon: + totalWidth = misc::max (totalWidth, totalMin); + + // The actual calculation is rather simple, the ith value is: + // + // + // (max[i] - min[i]) * (totalMax - totalMin) + // width[i] = totalMin + ----------------------------------------- + // (totalWidth - totalMin) + // + // (Regard "total" as "sum".) With the following general + // definitions (for both the list and sums): + // + // diffExtr = max - min + // diffWidth = width - min + // + // it is simplified to: + // + // diffExtr[i] * totalDiffWidth + // diffWidth[i] = ---------------------------- + // totalDiffExtr + // + // Of course, if totalDiffExtr is 0, this is not defined; + // instead, we apportion according to the minima: + // + // min[i] * totalWidth + // width[i] = ------------------- + // totalMin + // + // Since min[i] <= max[i] for all i, totalMin == totalMax + // implies that min[i] == max[i] for all i. + // + // Third, it totalMin == 0 (which also implies min[i] = max[i] = 0), + // the result is + // + // width[i] = totalWidth / n + + int totalDiffExtr = totalMax - totalMin; + if (totalDiffExtr != 0) { + // Normal case. The algorithm described in + // "rounding-errors.doc" is used, with: + // + // x[i] = diffExtr[i] + // y[i] = diffWidth[i] + // a = totalDiffWidth + // b = totalDiffExtr + + DBG_OBJ_MSG ("resize", 1, "normal case"); + + int totalDiffWidth = totalWidth - totalMin; + int cumDiffExtr = 0, cumDiffWidth = 0; + + for (int col = firstCol; col <= lastCol; col++) { + int min = getColExtreme (col, minExtrMod); + int max = getColExtreme (col, maxExtrMod); + int diffExtr = max - min; + + cumDiffExtr += diffExtr; + int diffWidth = + (cumDiffExtr * totalDiffWidth) / totalDiffExtr - cumDiffWidth; + cumDiffWidth += diffWidth; + + dest->set (destOffset - firstCol + col, diffWidth + min); + } + } else if (totalMin != 0) { + // Special case. Again, same algorithm, with + // + // x[i] = min[i] + // y[i] = width[i] + // a = totalWidth + // b = totalMin + + DBG_OBJ_MSG ("resize", 1, "special case 1"); + + int cumMin = 0, cumWidth = 0; + for (int col = firstCol; col <= lastCol; col++) { + int min = getColExtreme (col, minExtrMod); + cumMin += min; + int width = (cumMin * totalWidth) / totalMin - cumWidth; + cumWidth += width; + + dest->set (destOffset - firstCol + col, width); + } + } else if (totalMin != 0) { + // Last special case. Ssame algorithm, with + // + // x[i] = 1 (so cumX = i = col - firstCol + 1) + // y[i] = width[i] + // a = totalWidth + // b = n = lastCol - firstCol + 1 + + DBG_OBJ_MSG ("resize", 1, "special case 2"); + + int cumWidth = 0, n = (lastCol - firstCol + 1); + for (int col = firstCol; col <= lastCol; col++) { + int i = (col - firstCol + 1); + int width = (i * totalWidth) / n - cumWidth; + cumWidth += width; + + dest->set (destOffset - firstCol + col, width); + } } } diff --git a/dw/table.hh b/dw/table.hh index ca6f8be4..186f1f50 100644 --- a/dw/table.hh +++ b/dw/table.hh @@ -423,7 +423,7 @@ private: core::Extremes *cellExtremes, ExtrMod minExtrMod, ExtrMod maxExtrMod); - void apportion2 (int width, int firstCol, int lastCol, + void apportion2 (int totalWidth, int firstCol, int lastCol, ExtrMod minExtrMod, ExtrMod maxExtrMod, lout::misc::SimpleVector<int> *dest, int destOffset); |