Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "packager.h"
- #include "renderarea.h"
- #include <QFile>
- #include <QTextStream>
- #include <QtAlgorithms>
- #include <cmath>
- ///////////////////////////////////////////////////////////////////////////////
- // Packager class implementation
- ///////////////////////////////////////////////////////////////////////////////
- void Packager::init(QString filename) {
- QFile file(filename);
- _rectangles.clear();
- if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- QTextStream in(&file);
- while (!in.atEnd()) {
- QStringList line = in.readLine().split(",");
- QRect rect;
- if (!line.isEmpty()) {
- rect.setRect(0, 0, line[0].toInt(), line[1].toInt());
- _rectangles.push_back(rect);
- }
- }
- }
- file.close();
- }
- int Packager::getSize(void)
- {
- return rectangles.size();
- }
- void Packager::UseAlgorithm(void)
- {
- rectangles.clear();
- rectangles = algorithm->pack(_rectangles);
- }
- void Packager::SetAlgorithm(Algorithm *a)
- {
- algorithm = a;
- }
- const QRect Packager::Level::put(const QRect &rect, bool f, bool leftJustified)
- {
- QRect newRect;
- if (f) {
- if (leftJustified) {
- newRect.setRect(floor, RenderArea::STRIPH - (bottom + rect.height() + 1),
- rect.width(), rect.height());
- } else {
- // 'ceiling' is used for right-justified rectangles packed on the floor
- newRect.setRect(RenderArea::STRIPW - (ceiling + rect.width()),
- RenderArea::STRIPH - (bottom + rect.height() + 1),
- rect.width(), rect.height());
- ceiling += rect.width();
- }
- floor += rect.width();
- } else {
- newRect.setRect(RenderArea::STRIPW - (ceiling + rect.width()),
- RenderArea::STRIPH - (bottom + height + 1),
- rect.width(), rect.height());
- ceiling += rect.width();
- }
- return newRect;
- }
- bool Packager::Level::ceilingFeasible(const QRect &rect, const QList<QRect> existing)
- {
- QRect testRect;
- testRect.setRect(RenderArea::STRIPW - (ceiling + rect.width()),
- RenderArea::STRIPH - (bottom + height + 1),
- rect.width(), rect.height());
- bool intersected = false;
- for (int i = 0; i < existing.size(); i++) {
- if (testRect.intersects(existing[i])) {
- intersected = true;
- break;
- }
- }
- bool fit = rect.width() <= (RenderArea::STRIPW - ceiling - initW);
- return fit && !intersected;
- }
- bool Packager::Level::floorFeasible(const QRect &rect)
- {
- return rect.width() <= (RenderArea::STRIPW - floor);
- }
- int Packager::Level::getSpace(bool f)
- {
- if (f) {
- return RenderArea::STRIPW - floor;
- } else {
- return RenderArea::STRIPW - ceiling - initW;
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Algorithm class implementation
- ///////////////////////////////////////////////////////////////////////////////
- static bool decreasingHeightComparsion(const QRect &r1, const QRect &r2)
- {
- return r1.height() >= r2.height();
- }
- static bool decreasingWidthComparsion(const QRect &r1, const QRect &r2)
- {
- return r1.width() >= r2.width();
- }
- const QList<QRect> NFDH::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<Packager::Level> levels;
- Packager::Level level(0, unpacked[0].height());
- QList<QRect> packed;
- packed.push_back(level.put(unpacked[0]));
- levels.push_back(level);
- for (int i = 1; i < unpacked.size(); i++) {
- if (levels.last().floorFeasible(unpacked[i])) {
- packed.push_back(levels.last().put(unpacked[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[i].height());
- packed.push_back(newLevel.put(unpacked[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> FFDH::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<Packager::Level> levels;
- Packager::Level level(0, unpacked[0].height());
- QList<QRect> packed;
- packed.push_back(level.put(unpacked[0]));
- levels.push_back(level);
- for (int i = 1; i < unpacked.size(); i++) {
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if (levels[j].floorFeasible(unpacked[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(unpacked[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[i].height());
- packed.push_back(newLevel.put(unpacked[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> BFDH::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<Packager::Level> levels;
- Packager::Level level(0, unpacked[0].height());
- QList<QRect> packed;
- packed.push_back(level.put(unpacked[0]));
- levels.push_back(level);
- for (int i = 1; i < unpacked.size(); i++) {
- int found = -1;
- int min = RenderArea::STRIPW;
- for (int j = 0; j < levels.size(); j++) {
- if (levels[j].floorFeasible(unpacked[i])) {
- if (levels[j].getSpace() < min) {
- found = j;
- min = levels[j].getSpace();
- }
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(unpacked[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[i].height());
- packed.push_back(newLevel.put(unpacked[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> KP01::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<Packager::Level> levels;
- QList<QRect> packed;
- int b = 0;
- while (!unpacked.isEmpty()) {
- Packager::Level level(b, unpacked.first().height());
- levels.push_back(level);
- b += unpacked.first().height();
- packed.push_back(levels.last().put(unpacked.first()));
- unpacked.removeFirst();
- // build dynamic matrix for KP01 instance
- int maxWidth = RenderArea::STRIPW - packed.last().width();
- QVector<QVector<int> > knap;
- for (int i = 0; i < unpacked.size() + 1; i++) {
- QVector<int> inner(maxWidth);
- inner[0] = 0;
- knap.push_back(inner);
- }
- for (int k = 1; k <= unpacked.size(); k++) {
- for (int y = 1; y <= maxWidth; y++) {
- if (y < unpacked[k - 1].width()) {
- knap[k][y - 1] = knap[k - 1][y - 1];
- } else if (y > unpacked[k - 1].width()) {
- knap[k][y - 1] = qMax(knap[k - 1][y - 1],
- knap[k - 1][y - 1 - unpacked[k - 1].width()]
- + unpacked[k - 1].width()*unpacked[k - 1].height());
- } else {
- knap[k][y - 1] = qMax(knap[k - 1][y - 1],
- unpacked[k - 1].width()*unpacked[k - 1].height());
- }
- }
- }
- // find solution using the matrix
- int k = unpacked.size();
- int solution[k];
- for (int j = 0; j < k; j++) {
- solution[j] = 0;
- }
- while(k > 0 && maxWidth > 0)
- {
- if(knap[k][maxWidth - 1]!=knap[k-1][maxWidth - 1])
- {
- solution[k-1]=1;
- maxWidth -= unpacked[k-1].width();
- }
- k--;
- }
- // pack selected rectangles
- int removed = 0;
- for (int i = 0; i < unpacked.size(); i++) {
- if (solution[i]) {
- packed.push_back(levels.last().put(unpacked[i - removed]));
- unpacked.removeAt(i - removed); // when remove, index is shifted
- removed++;
- }
- }
- }
- return packed;
- }
- const QList<QRect> SF::pack(const QList<QRect> rects)
- {
- QList<Sf> unpacked;
- QList<QRect> selected;
- // without loss of generality, all dimensions are scaled to Strip Width.
- for (int i = 0; i < rects.size(); i++) {
- Sf scaledRect;
- scaledRect.rect = rects[i];
- scaledRect.scaledWidth = static_cast<qreal>(rects[i].width())
- / static_cast<qreal>(RenderArea::STRIPW);
- scaledRect.packedFirst = (scaledRect.scaledWidth > static_cast<qreal>(1)
- / static_cast<qreal>(2));
- unpacked.push_back(scaledRect);
- if ( scaledRect.packedFirst
- && scaledRect.scaledWidth > static_cast<qreal>(2)
- / static_cast<qreal>(3)) {
- selected.push_back(rects[i]);
- }
- }
- QList<Packager::Level> levels;
- QList<QRect> packed;
- if (!selected.isEmpty()) {
- qSort(selected.begin(), selected.end(), decreasingHeightComparsion);
- // pack selected rectangles those of with > 2/3 using FFDH on L1
- Packager::Level level(0, selected[0].height());
- packed.push_back(level.put(selected[0]));
- levels.push_back(level);
- for (int i = 1; i < selected.size(); i++) {
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if (levels[j].floorFeasible(selected[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(selected[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- selected[i].height());
- packed.push_back(newLevel.put(selected[i]));
- levels.push_back(newLevel);
- }
- }
- }
- // pack selected rectangles those of with <= 2/3 using FFDH (from the next level)
- selected.clear();
- for (int i = 0; i < unpacked.size(); i++) {
- if ( unpacked[i].packedFirst
- && unpacked[i].scaledWidth <= static_cast<qreal>(2)
- / static_cast<qreal>(3)) {
- selected.push_back(unpacked[i].rect);
- }
- }
- int nextLevelInd = levels.size();
- if (!selected.isEmpty()) {
- qSort(selected.begin(), selected.end(), decreasingWidthComparsion);
- Packager::Level nextLevel(levels.last().bottom + levels.last().height,
- selected[0].height());
- packed.push_back(nextLevel.put(selected[0]));
- levels.push_back(nextLevel);
- for (int i = 1; i < selected.size(); i++) {
- int found = -1;
- for (int j = nextLevelInd; j < levels.size(); j++) {
- if (levels[j].floorFeasible(selected[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(selected[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- selected[i].height());
- packed.push_back(newLevel.put(selected[i]));
- levels.push_back(newLevel);
- }
- }
- }
- // calc the R region
- int regionBottom = levels[nextLevelInd].bottom;
- int regionWidth = levels[nextLevelInd].getSpace();
- int regionHeight = 0;
- for (int i = nextLevelInd; i < levels.size(); i++) {
- regionHeight += levels[i].height;
- }
- // pack selected rectangles those of with > 2/3 into R
- selected.clear();
- for (int i = 0; i < unpacked.size(); i++) {
- if (!unpacked[i].packedFirst) {
- selected.push_back(unpacked[i].rect);
- }
- }
- if (!selected.isEmpty()) {
- qSort(selected.begin(), selected.end(), decreasingHeightComparsion);
- QList<Packager::Level> regionLevels;
- int fit = 0;
- QList<QRect> remaining;
- while (selected[fit].height() > regionHeight) {
- remaining.push_back(selected[fit++]);
- }
- Packager::Level rLevel(regionBottom, selected[fit].height(),
- RenderArea::STRIPW - regionWidth);
- packed.push_back(rLevel.put(selected[fit]));
- regionLevels.push_back(rLevel);
- int regionCapacity = regionHeight - rLevel.height;
- for (int i = fit + 1; i < selected.size(); i++) {
- int found = -1;
- for (int j = 0; j < regionLevels.size(); j++) {
- if (regionLevels[j].floorFeasible(selected[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) { // space on existing level in R
- packed.push_back(regionLevels[found].put(selected[i]));
- } else if (selected[i].height() <= regionCapacity ){ // remaining space of R
- Packager::Level newLevel(regionLevels.last().bottom + regionLevels.last().height,
- selected[i].height(), RenderArea::STRIPW - regionWidth);
- packed.push_back(newLevel.put(selected[i]));
- regionLevels.push_back(newLevel);
- regionCapacity -= newLevel.height;
- } else { // no space, skip
- remaining.push_back(selected[i]);
- }
- }
- if (!remaining.isEmpty()) { // pack all other over L1
- int overInd = levels.size();
- Packager::Level level(levels.last().bottom + levels.last().height,
- remaining[0].height());
- packed.push_back(level.put(remaining[0]));
- levels.push_back(level);
- for (int i = 1; i < remaining.size(); i++) {
- int found = -1;
- for (int j = overInd; j < levels.size(); j++) {
- if (levels[j].floorFeasible(remaining[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(remaining[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- remaining[i].height());
- packed.push_back(newLevel.put(remaining[i]));
- levels.push_back(newLevel);
- }
- }
- }
- }
- return packed;
- }
- const QList<QRect> JOIN::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<QRect> joined = unpacked;
- int j = 0;
- int removed = 0;
- while (j + 1 < unpacked.size()) {
- if ( static_cast<qreal>((unpacked[j].height() - unpacked[j + 1].height()))
- / static_cast<qreal>(unpacked[j].height()) <= _gamma
- && unpacked[j].width() + unpacked[j + 1].width() <= RenderArea::STRIPW) {
- joined[j - removed].setWidth(unpacked[j].width() + unpacked[j + 1].width());
- joined.removeAt(j + 1 - removed++);
- j++;
- }
- j++;
- }
- // pack with FFDH
- QList<Packager::Level> levels;
- Packager::Level level(0, unpacked[0].height());
- QList<QRect> packedFFDH;
- int rectInd = 0;
- int joinInd = 0;
- packedFFDH.push_back(level.put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedFFDH.push_back(level.put(unpacked[rectInd++]));
- }
- levels.push_back(level);
- while (joinInd < joined.size()) {
- int found = -1;
- for (int k = 0; k < levels.size(); k++) {
- if (levels[k].floorFeasible(joined[joinInd])) {
- found = k;
- break;
- }
- }
- if (found > -1) {
- packedFFDH.push_back(levels[found].put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedFFDH.push_back(levels[found].put(unpacked[rectInd++]));
- }
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[rectInd].height());
- packedFFDH.push_back(newLevel.put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedFFDH.push_back(newLevel.put(unpacked[rectInd++]));
- }
- levels.push_back(newLevel);
- }
- }
- int packHeightFFDH = levels.last().bottom + levels.last().height;
- // pack with NFDH
- levels.clear();
- Packager::Level l(0, unpacked[0].height());
- QList<QRect> packedNFDH;
- rectInd = 0;
- joinInd = 0;
- packedNFDH.push_back(l.put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedNFDH.push_back(l.put(unpacked[rectInd++]));
- }
- levels.push_back(l);
- while (joinInd < joined.size()) {
- if (levels.last().floorFeasible(joined[joinInd])) {
- packedNFDH.push_back(levels.last().put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedNFDH.push_back(levels.last().put(unpacked[rectInd++]));
- }
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[rectInd].height());
- packedNFDH.push_back(newLevel.put(unpacked[rectInd]));
- if (joined[joinInd++].width() > unpacked[rectInd++].width()) {
- packedNFDH.push_back(newLevel.put(unpacked[rectInd++]));
- }
- levels.push_back(newLevel);
- }
- }
- return (levels.last().bottom + levels.last().height < packHeightFFDH)
- ? packedNFDH
- : packedFFDH;
- }
- const QList<QRect> FCNR::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- QList<Packager::Level> levels;
- Packager::Level level(0, unpacked[0].height(), 0, unpacked[0].width());
- QList<QRect> packed;
- packed.push_back(level.put(unpacked[0]));
- levels.push_back(level);
- for (int i = 1; i < unpacked.size(); i++) {
- int found = -1;
- int min = RenderArea::STRIPW;
- for (int j = 0; j < levels.size(); j++) {
- if (levels[j].floorFeasible(unpacked[i])) {
- if (levels[j].getSpace() < min) {
- found = j;
- min = levels[j].getSpace();
- }
- }
- }
- if (found > -1) { // floor-pack on existing level
- packed.push_back(levels[found].put(unpacked[i]));
- } else {
- int found = -1;
- int min = RenderArea::STRIPW;
- for (int j = 0; j < levels.size(); j++) {
- if (levels[j].ceilingFeasible(unpacked[i], packed)) {
- if (levels[j].getSpace(false) < min) {
- found = j;
- min = levels[j].getSpace(false);
- }
- }
- }
- if (found > -1) { // ceiling-pack on existing level
- packed.push_back(levels[found].put(unpacked[i], false));
- } else { // a new level
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- unpacked[i].height(), 0, unpacked[i].width());
- packed.push_back(newLevel.put(unpacked[i]));
- levels.push_back(newLevel);
- }
- }
- }
- return packed;
- }
- const QList<QRect> Sleator::pack(const QList<QRect> rects)
- {
- QList<QRect> unpacked;
- QList<QRect> selected;
- // select rectangles wider than 1/2 of Strip Width.
- for (int i = 0; i < rects.size(); i++) {
- if (rects[i].width() > RenderArea::STRIPW / 2) {
- selected.push_back(rects[i]);
- } else {
- unpacked.push_back(rects[i]);
- }
- }
- QList<QRect> packed;
- int hStack = 0;
- // stack rectangles of width greater than 1/2, if any
- for (int i = 0; i < selected.size(); i++) {
- QRect newRect;
- newRect.setRect(0, RenderArea::STRIPH - (hStack + selected[i].height() + 1),
- selected[i].width(), selected[i].height());
- packed.push_back(newRect);
- hStack += selected[i].height();
- }
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- int hLeft = hStack + unpacked[0].height();
- int hRight = 0;
- int ind = 0;
- int x = 0;
- while (unpacked[ind].width() <= RenderArea::STRIPW - x) { // pack layer, compute hLeft, hRight
- QRect newRect;
- newRect.setRect(x, RenderArea::STRIPH - (hStack + unpacked[ind].height() + 1),
- unpacked[ind].width(), unpacked[ind].height());
- packed.push_back(newRect);
- x += unpacked[ind].width();
- if (hRight == 0 && x >= RenderArea::STRIPW / 2) {
- hRight = hStack + unpacked[ind].height();
- }
- ind++;
- }
- while (ind < unpacked.size()) { // pack remaining
- QRect newRect;
- if (hRight < hLeft && unpacked[ind].width() <= RenderArea::STRIPW / 2) {
- newRect.setRect(RenderArea::STRIPW / 2,
- RenderArea::STRIPH - (hRight + unpacked[ind].height() + 1),
- unpacked[ind].width(), unpacked[ind].height());
- hRight += unpacked[ind].height();
- } else {
- newRect.setRect(0, RenderArea::STRIPH - (hLeft + unpacked[ind].height() + 1),
- unpacked[ind].width(), unpacked[ind].height());
- hLeft += unpacked[ind].height();
- }
- packed.push_back(newRect);
- ind++;
- }
- return packed;
- }
- const QList<QRect> Burke::pack(const QList<QRect> rects)
- {
- QList<int> gap;
- QList<QRect> unpacked = rects;
- qSort(unpacked.begin(), unpacked.end(), decreasingHeightComparsion);
- qSort(unpacked.begin(), unpacked.end(), decreasingWidthComparsion);
- for (int i = 0; i < RenderArea::STRIPW; i++) {
- gap.push_back(0);
- }
- QList<QRect> packed;
- while (!unpacked.isEmpty()) {
- // find lowest gap
- int min = gap[0];
- int coordX = 0;
- for (int i = 1; i < gap.size(); i++) {
- if (gap[i] < min) {
- min = gap[i];
- coordX = i;
- }
- }
- int i = coordX + 1;
- int gapWidth = 1;
- while (i < gap.size() && gap[i] == gap[i - 1]) {
- gapWidth++;
- i++;
- }
- // find best fitting rectangle
- int ind = -1;
- qreal fit = 0.0;
- for (int j = 0; j < unpacked.size(); j++) {
- qreal curFit = static_cast<qreal>(unpacked[j].width())
- / static_cast<qreal>(gapWidth);
- if (curFit < static_cast<qreal>(1) && curFit > fit) {
- fit = curFit;
- ind = j;
- }
- }
- if (ind > -1) {
- // place best fitting rectangle using placement policy 'Leftmost'
- QRect newRect;
- newRect.setRect(coordX,
- RenderArea::STRIPH - (gap[coordX] + unpacked[ind].height()),
- unpacked[ind].width(), unpacked[ind].height());
- packed.push_back(newRect);
- // raise elements of array to appropriate height
- for (int j = coordX; j < coordX + unpacked[ind].width(); j++) {
- gap[j] += unpacked[ind].height();
- }
- unpacked.removeAt(ind);
- } else {
- // raise gap to height of the lowest neighbour
- int lowest;
- if (coordX == 0) {
- lowest = gap[gapWidth];
- } else if (coordX + gapWidth == gap.size()) {
- lowest = gap[gap.size() - gapWidth - 1];
- } else if (gap[coordX - 1] < gap[coordX + gapWidth]) {
- lowest = gap[coordX - 1];
- } else {
- lowest = gap[coordX + gapWidth];
- }
- for (int j = coordX; j < coordX + gapWidth; j++) {
- gap[j] = lowest;
- }
- }
- }
- return packed;
- }
- /////////////////////////////////////////////////////////////////////////////////////////
- const QList<QRect> NFL::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, rects[0].height());
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- if (levels.last().floorFeasible(rects[i])) {
- packed.push_back(levels.last().put(rects[i]));
- if (levels.last().height < rects[i].height()) {
- levels.last().height = rects[i].height();
- }
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- rects[i].height());
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> FFL::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, rects[0].height());
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if ( (levels[j].height >= rects[i].height() || j == levels.size() - 1)
- && levels[j].floorFeasible(rects[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- if ( found == (levels.size() - 1)
- && levels[found].height < rects[i].height()) {
- levels[found].height = rects[i].height();
- }
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- rects[i].height());
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> BFL::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, rects[0].height());
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- int min = RenderArea::STRIPW;
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if ( (levels[j].height >= rects[i].height() || j == levels.size() - 1)
- && levels[j].floorFeasible(rects[i])
- && levels[j].getSpace() - rects[i].width() < min) {
- found = j;
- min = levels[j].getSpace() - rects[i].width();
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- if ( found == (levels.size() - 1)
- && levels[found].height < rects[i].height()) {
- levels[found].height = rects[i].height();
- }
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- rects[i].height());
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> BiNFL::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- int highest = rects[0].height();
- int bottom = 0;
- int ind = 0;
- while (ind < rects.size()) {
- int i = ind;
- //create a new bi-level
- Packager::Level lowerLevel(bottom, 0);
- // pack on lower level
- // first rectangle is packed left-justified
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++]));
- // subsequent rectangles that fit are right justified
- while(ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- }
- if (ind < rects.size()) {
- bottom += highest;
- highest = rects[ind].height();
- Packager::Level upperLevel(bottom, 0);
- // pack on upper level
- if (ind == i + 1) {
- // left justified
- packed.push_back(upperLevel.put(rects[ind++]));
- } else if (ind == i + 2) {
- // pack above min
- if (rects[ind - 1].height() < rects[ind - 2].height()) {
- packed.push_back(upperLevel.put(rects[ind++], true, false));
- } else {
- packed.push_back(upperLevel.put(rects[ind++]));
- }
- }
- while(ind < rects.size() && upperLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(upperLevel.put(rects[ind++], true, false));
- }
- }
- bottom += highest;
- highest = 0;
- }
- return packed;
- }
- const QList<QRect> NFS::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, pow(_base, round(log(rects[0].height()) / log(_base)) - 1));
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- // compute k
- qreal k = log(rects[i].height()) / log(_base);
- int aprHeight = static_cast<int>(pow(_base, round(k) - 1));
- // pack if fit
- if ( rects[i].height() <= levels.last().height
- && levels.last().floorFeasible(rects[i])) {
- packed.push_back(levels.last().put(rects[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- aprHeight);
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> FFS::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, pow(_base, round(log(rects[0].height()) / log(_base)) - 1));
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- // compute k
- qreal k = log(rects[i].height()) / log(_base);
- int aprHeight = static_cast<int>(pow(_base, round(k) - 1));
- // search for lower shelf of appr. height with suff. space
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if ( rects[i].height() <= levels[j].height
- && levels[j].floorFeasible(rects[i])) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- aprHeight);
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> BFS::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, pow(_base, round(log(rects[0].height()) / log(_base)) - 1));
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- for (int i = 1; i < rects.size(); i++) {
- // compute k
- qreal k = log(rects[i].height()) / log(_base);
- int aprHeight = static_cast<int>(pow(_base, round(k) - 1));
- // search for shelf of appr. height with best space
- int min = RenderArea::STRIPW;
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if ( rects[i].height() <= levels[j].height
- && levels[j].floorFeasible(rects[i])
- && levels[j].getSpace() - rects[i].width() < min) {
- found = j;
- min = levels[j].getSpace() - rects[i].width();
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- aprHeight);
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- }
- }
- return packed;
- }
- const QList<QRect> HS::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- QList<int> widths;
- Packager::Level level(0, pow(_base, round(log(rects[0].height()) / log(_base)) - 1));
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- int p = 1;
- while (p < 4 && static_cast<qreal>(rects[0].width())
- / static_cast<qreal>(RenderArea::STRIPW)
- < static_cast<qreal>(1)
- / static_cast<qreal>(p + 1)) p++;
- widths.push_back(p);
- for (int i = 1; i < rects.size(); i++) {
- // compute k
- qreal k = log(rects[i].height()) / log(_base);
- int aprHeight = static_cast<int>(pow(_base, round(k) - 1));
- // compute p. M = 4
- p = 1;
- while (p < 4 && static_cast<qreal>(rects[i].width())
- / static_cast<qreal>(RenderArea::STRIPW)
- < static_cast<qreal>(1)
- / static_cast<qreal>(p + 1)) p++;
- int found = -1;
- for (int j = 0; j < levels.size(); j++) {
- if ( rects[i].height() <= levels[j].height
- && levels[j].floorFeasible(rects[i])
- && widths[j] == p) {
- found = j;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- aprHeight);
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- widths.push_back(p);
- }
- }
- return packed;
- }
- const QList<QRect> Azar::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<Packager::Level> levels;
- Packager::Level level(0, rects[0].height());
- packed.push_back(level.put(rects[0]));
- levels.push_back(level);
- QList<qreal> widths;
- widths.push_back(round(log(rects[0].width()) / log(2)));
- for (int i = 1; i < rects.size(); i++) {
- // compute x
- qreal x = round(log(rects[i].width()) / log(2));
- if ( static_cast<qreal>(rects[i].width())
- / static_cast<qreal>(RenderArea::STRIPW) >= _gamma) {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- rects[i].height());
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- widths.push_back(x);
- } else {
- // compute j
- qreal j = log(rects[i].height()) / log(2);
- int found = -1;
- for (int k = 0; k < levels.size(); k++) {
- if ( levels[k].floorFeasible(rects[i])
- && levels[k].height >= rects[i].height()
- && widths[k] == x) {
- found = k;
- break;
- }
- }
- if (found > -1) {
- packed.push_back(levels[found].put(rects[i]));
- } else {
- Packager::Level newLevel(levels.last().bottom + levels.last().height,
- pow(2, round(j) + 1));
- packed.push_back(newLevel.put(rects[i]));
- levels.push_back(newLevel);
- widths.push_back(x);
- }
- }
- }
- return packed;
- }
- const QList<QRect> CA::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- int highest = rects[0].height();
- int bottom = 0;
- int ind = 0;
- while (ind < rects.size()) {
- //create a new bi-level
- Packager::Level lowerLevel(bottom, 0);
- // pack on lower level
- // first rectangle is packed left-justified
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++]));
- int shiftTo = packed.last().y() - 1;
- bool leftJustified = true;
- // subsequent rectangles that fit are right justified
- // note if 2nd rectangle is lower
- if (ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) {
- highest = rects[ind].height();
- } else {
- leftJustified = false;
- }
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- if (!leftJustified) shiftTo = packed.last().y() - 1;
- }
- // pack remaining
- while(ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- }
- if (ind < rects.size()) {
- bottom += highest;
- highest = rects[ind].height();
- Packager::Level upperLevel(bottom, 0);
- // pack on upper level
- // first packed should be justified according to the shorter
- packed.push_back(upperLevel.put(rects[ind++], true, leftJustified));
- // and shifted downwards, if possible
- if (shiftTo - packed.last().bottom() >= packed.last().height()) {
- bool intersect = false;
- QRect tryRect = packed.last();
- tryRect.moveBottom(shiftTo);
- for (int i = 0; i < packed.size() - 1; i++) {
- intersect = packed[i].intersects(tryRect);
- if (intersect) break;
- }
- if (!intersect) packed.last().moveBottom(shiftTo);
- }
- // remaining - right justified
- while(ind < rects.size() && upperLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(upperLevel.put(rects[ind++], true, false));
- }
- }
- bottom += highest;
- highest = 0;
- }
- return packed;
- }
- const QList<QRect> CPF::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- int highest = rects[0].height();
- int bottom = 0;
- int ind = 0;
- QList<int> gap;
- for (int i = 0; i < RenderArea::STRIPW; i++) gap.push_back(-1);
- while (ind < rects.size()) {
- //create a new bi-level
- Packager::Level lowerLevel(bottom, 0);
- for (int i = 0; i < gap.size(); i++) gap[i] = bottom;
- // pack on lower level
- // first rectangle is packed left-justified
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++]));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- // subsequent rectangles that fit are right justified
- while(ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- }
- if (ind < rects.size()) {
- bottom += highest;
- highest = 0;
- Packager::Level upperLevel(bottom, 0);
- // pack on upper level left justified with sliding
- while(ind < rects.size() && upperLevel.floorFeasible(rects[ind])) {
- // check if rectangle may be shifted down
- int shiftTo = bottom;
- for (int i = upperLevel.floor; i < upperLevel.floor + rects[ind].width(); i++) {
- if (bottom - gap[i] < shiftTo) shiftTo = bottom - gap[i];
- }
- if (shiftTo < rects[ind].height()) {
- // pack and shift
- if (rects[ind].height() - shiftTo > highest) highest = rects[ind].height() - shiftTo;
- packed.push_back(upperLevel.put(rects[ind++]));
- packed.last().adjust(0, shiftTo, 0, shiftTo);
- } else {
- // just pack
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(upperLevel.put(rects[ind++]));
- }
- }
- }
- bottom += highest;
- highest = 0;
- }
- return packed;
- }
- const QList<QRect> CFF::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- int highest = rects[0].height();
- int bottom = 0;
- int ind = 0;
- QList<int> gap;
- for (int i = 0; i < RenderArea::STRIPW; i++) gap.push_back(-1);
- while (ind < rects.size()) {
- //create a new bi-level
- Packager::Level lowerLevel(bottom, 0);
- for (int i = 0; i < gap.size(); i++) gap[i] = bottom;
- // pack on lower level
- // first rectangle is packed left-justified
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++]));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- // subsequent rectangles that fit are right justified
- while(ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- }
- if (ind < rects.size()) {
- bottom += highest;
- highest = 0;
- Packager::Level upperLevel(bottom, 0);
- // pack on upper level left justified with sliding
- while(ind < rects.size() && upperLevel.floorFeasible(rects[ind])) {
- // check if rectangle may be shifted down
- int shiftTo = bottom;
- int topIndex;
- for (int i = upperLevel.floor; i < upperLevel.floor + rects[ind].width(); i++) {
- if (bottom - gap[i] < shiftTo) {
- shiftTo = bottom - gap[i];
- topIndex = i;
- }
- }
- if (shiftTo >= rects[ind].height()) {
- // highest does not change
- // pack and shift
- packed.push_back(upperLevel.put(rects[ind++]));
- packed.last().adjust(0, shiftTo, 0, shiftTo);
- // release upper level
- upperLevel.floor -= rects[ind - 1].width();
- // recalc gap
- for (int i = upperLevel.floor; i < upperLevel.floor + rects[ind - 1].width(); i++) {
- gap[i] = gap[topIndex] + rects[ind - 1].height();
- }
- } else {
- // just pack
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(upperLevel.put(rects[ind++]));
- }
- }
- }
- bottom += highest;
- highest = 0;
- }
- return packed;
- }
- const QList<QRect> CC::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- int highest = rects[0].height();
- int bottom = 0;
- int ind = 0;
- QList<int> gap;
- for (int i = 0; i < RenderArea::STRIPW; i++) gap.push_back(-1);
- while (ind < rects.size()) {
- //create a new bi-level
- Packager::Level lowerLevel(bottom, 0);
- for (int i = 0; i < gap.size(); i++) gap[i] = bottom;
- // pack on lower level
- // first rectangle is packed left-justified
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++]));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- // subsequent rectangles that fit are right justified
- while(ind < rects.size() && lowerLevel.floorFeasible(rects[ind])) {
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(lowerLevel.put(rects[ind++], true, false));
- for (int i = packed.last().x(); i < packed.last().x() + packed.last().width(); i++) {
- gap[i] += packed.last().height();
- }
- }
- if (ind < rects.size()) {
- bottom += highest;
- highest = 0;
- Packager::Level upperLevel(bottom, 0);
- // pack on upper level left justified with sliding
- while(ind < rects.size() && upperLevel.floorFeasible(rects[ind])) {
- // check if rectangle may be shifted down
- int shiftTo = bottom;
- int topIndex;
- for (int i = upperLevel.floor; i < upperLevel.floor + rects[ind].width(); i++) {
- if (bottom - gap[i] < shiftTo) {
- shiftTo = bottom - gap[i];
- topIndex = i;
- }
- }
- if (shiftTo > 0) {
- if (shiftTo < rects[ind].height()) {
- // pack and shift
- if (rects[ind].height() - shiftTo > highest) highest = rects[ind].height() - shiftTo;
- packed.push_back(upperLevel.put(rects[ind++]));
- packed.last().adjust(0, shiftTo, 0, shiftTo);
- } else {
- // highest does not change
- // pack and shift
- packed.push_back(upperLevel.put(rects[ind++]));
- packed.last().adjust(0, shiftTo, 0, shiftTo);
- // release upper level
- upperLevel.floor -= rects[ind - 1].width();
- // recalc gap
- for (int i = upperLevel.floor; i < upperLevel.floor + rects[ind - 1].width(); i++) {
- gap[i] = gap[topIndex] + rects[ind - 1].height();
- }
- }
- } else {
- // just pack
- if (rects[ind].height() > highest) highest = rects[ind].height();
- packed.push_back(upperLevel.put(rects[ind++]));
- }
- }
- }
- bottom += highest;
- highest = 0;
- }
- return packed;
- }
- const QList<QRect> OF::pack(const QList<QRect> rects)
- {
- QList<QRect> packed;
- QList<int> gap;
- QList<QRect> emptyAreas;
- int ind;
- for (int i = 0; i < RenderArea::STRIPW; i++) gap.push_back(0);
- for (ind = 0; ind < rects.size(); ind++) {
- // Search the list of empty areas for sufficient space to pack
- if (!emptyAreas.isEmpty()) {
- int fitInd = -1;
- for (int i = 0; i < emptyAreas.size(); i++) {
- if ( emptyAreas[i].width() >= rects[ind].width()
- && emptyAreas[i].height() >= rects[ind].height()) {
- fitInd = i;
- break;
- }
- }
- if (fitInd > -1) {
- // pack into empty area
- QRect toPack;
- toPack.setRect(emptyAreas[fitInd].x(),
- emptyAreas[fitInd].y() + emptyAreas[fitInd].height() - rects[ind].height(),
- rects[ind].width(), rects[ind].height());
- packed.push_back(toPack);
- // split area
- QRect newArea;
- if ( emptyAreas[fitInd].width() - rects[ind].width()
- > emptyAreas[fitInd].height() - rects[ind].height()) {
- // vertically
- newArea.setRect(emptyAreas[fitInd].x(), emptyAreas[fitInd].y(), rects[ind].width(),
- emptyAreas[fitInd].height() - rects[ind].height());
- emptyAreas.push_back(newArea);
- emptyAreas[fitInd].adjust(rects[ind].width(), 0, 0, 0);
- } else {
- // horizontally
- newArea.setRect(emptyAreas[fitInd].x() + rects[ind].width(),
- emptyAreas[fitInd].y() + emptyAreas[fitInd].height() - rects[ind].height(),
- emptyAreas[fitInd].width() - rects[ind].width(), rects[ind].height());
- emptyAreas.push_back(newArea);
- emptyAreas[fitInd].adjust(0, 0, 0, -rects[ind].height());
- }
- continue;
- }
- }
- // search the linear array for available packing width
- int index = searchMinGap(gap, rects[ind].width());
- // analyze packing place
- if (_level > gap[index]) {
- QRect emptyArea;
- int areaWidth = 0;
- int i = index;
- while (gap[i++] == gap[index]) {
- areaWidth++;
- }
- emptyArea.setRect(index, RenderArea::STRIPH - _level, areaWidth, _level - gap[index]);
- emptyAreas.push_back(emptyArea);
- } else {
- int level = gap[index];
- int areaIndex = index + 1;
- while (areaIndex < index + rects[ind].width()) {
- if (gap[areaIndex] < level) {
- QRect emptyArea;
- int areaWidth = 0;
- int x = areaIndex;
- level = gap[areaIndex];
- while (gap[areaIndex++] == level && areaIndex < index + rects[ind].width()) {
- areaWidth++;
- }
- emptyArea.setRect(x, RenderArea::STRIPH - gap[index], areaWidth, gap[index] - level);
- emptyAreas.push_back(emptyArea);
- } else {
- areaIndex++;
- }
- }
- }
- // pack
- QRect toPack;
- toPack.setRect(index, RenderArea::STRIPH - (_level + rects[ind].height()),
- rects[ind].width(), rects[ind].height());
- packed.push_back(toPack);
- // raise gap
- for (int i = index; i < index + rects[ind].width(); i++) {
- gap[i] = _level + rects[ind].height();
- }
- }
- return packed;
- }
- int OF::searchMinGap(const QList<int> gap, int width)
- {
- // find lowest gap
- int min = gap[0];
- int coordX = 0;
- for (int i = 1; i < gap.size(); i++) {
- if (gap[i] < min) {
- min = gap[i];
- coordX = i;
- }
- }
- int i = coordX + 1;
- int gapWidth = 1;
- while (i < gap.size() && gap[i] == gap[i - 1]) {
- gapWidth++;
- i++;
- }
- if (gapWidth >= width) {
- _level = gap[coordX];
- return coordX;
- } else {
- // if doesn't fit, raise gap to height of the lowest neighbour
- int lowest;
- if (coordX == 0) {
- lowest = gap[gapWidth];
- } else if (coordX + gapWidth == gap.size()) {
- lowest = gap[gap.size() - gapWidth - 1];
- } else if (gap[coordX - 1] < gap[coordX + gapWidth]) {
- lowest = gap[coordX - 1];
- } else {
- lowest = gap[coordX + gapWidth];
- }
- QList<int> newGap = gap;
- for (int j = coordX; j < coordX + gapWidth; j++) {
- newGap[j] = lowest;
- }
- // and search again
- return searchMinGap(newGap, width);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement