void IteratorOpParser::computeLimits(vector<Formula*>& mainSymbols, vector<unsigned int>& iteratorOpSymbolIndexes, unsigned int currentMainIndex, unsigned int currentItOpIndex, long* rightLimit, long* leftLimit) { unsigned int& k = currentMainIndex; unsigned int& i = currentItOpIndex; Formula* currentMainSymbol = mainSymbols.at(k); if (0 == k) { *leftLimit = maxLeftLimit; } else { Formula* previousMainSymbol = mainSymbols.at(k - 1); long prevRight = previousMainSymbol->right(); long distance = currentMainSymbol->left() - prevRight; if (i > 0 && iteratorOpSymbolIndexes.at(i - 1) == k - 1) { //il simbolo precedente è un IteratorOp *leftLimit = prevRight + distance / 2 + distance % 2; //la divisione è fra interi e quindi ci può essere arrotondamento } else { *leftLimit = prevRight + 1; } } if (mainSymbols.size() - 1 == k) { *rightLimit = maxRightLimit; } else { Formula* nextMainSymbol = mainSymbols.at(k + 1); long currentRight = currentMainSymbol->right(); long nextLeft = nextMainSymbol->left(); long distance = nextLeft - currentRight; if (i < iteratorOpSymbolIndexes.size() - 1 && iteratorOpSymbolIndexes.at(i + 1) == k + 1) { //il simbolo sucessivo è un IteratorOp *rightLimit = currentRight + distance / 2; //la divisione è fra interi e quindi ci può essere arrotondamento } else { *rightLimit = nextLeft - 1; } } }
vector<Formula*>& SubSupParser::rec_findSubSup(vector<Formula*>& allSymbols, vector<Formula*>& mainSymbols, vector<Formula*>& otherSymbols, unsigned int currentMainIndex, double formulaMidline) { unsigned int& i = currentMainIndex; if (i >= mainSymbols.size()) { return *(new vector<Formula*>()); } Formula* currentMain = mainSymbols.at(i); Formula* subscript = NULL; Formula* superscript = NULL; bool subformulaFound = true; while (subformulaFound && !otherSymbols.empty()) { Formula* currentOther = otherSymbols.at(0); //se alcuni simboli vengono classificati come apice/pedice, vengono rimossi dal vettore. Per questo motivo il simbolo "corrente" è sempre il primo int currentLeftLimit = currentMain->left(); int currentRightLimit = (i == mainSymbols.size() - 1) ? maxRightLimit : mainSymbols.at(i + 1)->left() - 1; bool currentOtherBetweenLimits = (currentLeftLimit <= currentOther->left() && currentOther->right() <= currentRightLimit); /* è possibile che il simbolo corrente sia un apice/pedice SE è completamente contenuto nell'intervallo (orizzontale) definito * dall'estremo sinistro del simbolo corrente fino all'estremo sinistro (escluso) del prossimo simbolo. Si prende l'estremo sinistro * e non il destro perché in questo modo si è sicuri che non ci sono "buchi" in cui * si può trovare un simbolo non principale: in alcuni casi, e.g. il simbolo di integrale, è necessario che il limite sia quello sinistro. */ double currentMainMidline = currentMain->center().getY(); bool aboveMidline = currentOther->center().getY() <= currentMainMidline; bool belowMidline = currentOther->center().getY() >= currentMainMidline; bool crossedByMidline = !aboveMidline && !belowMidline; if (currentOtherBetweenLimits) { if (!crossedByMidline && !Blacklist::inSubSupBlacklist(currentMain)) { if (belowMidline) { //pedice findSubSup(&subscript, currentOther, allSymbols, mainSymbols, otherSymbols, i, false); } else if (aboveMidline) { //apice findSubSup(&superscript, currentOther, allSymbols, mainSymbols, otherSymbols, i, true); } subformulaFound = true; } else { mainSymbols.insert(mainSymbols.begin() + i + 1, currentOther); otherSymbols.erase(otherSymbols.begin()); subformulaFound = false; } } else { subformulaFound = false; } } SubSup* newSubformula = new SubSup(currentMain, subscript, superscript); vector<Formula*>& tmpFormula = rec_findSubSup(allSymbols, mainSymbols, otherSymbols, i + 1, formulaMidline); tmpFormula.insert(tmpFormula.begin(), newSubformula); return tmpFormula; }
vector<Formula*>& IteratorOpParser::_parse(vector<Formula*>& formulaToParse) { vector<Formula*> mainSymbols, otherSymbols; vector<Formula*>& result = *(new vector<Formula*>()); findMainSymbols(formulaToParse, mainSymbols, otherSymbols, false); vector<unsigned int> iteratorOpSymbolIndexes = findIteratorOpSymbolIndexes(mainSymbols); unsigned int i = 0; for (unsigned int k = 0; k < mainSymbols.size(); k++) { Formula* currentMainSymbol = mainSymbols.at(k); if (i < iteratorOpSymbolIndexes.size() && iteratorOpSymbolIndexes.at(i) == k) { long currentLeftLimit, currentRightLimit; computeLimits(mainSymbols, iteratorOpSymbolIndexes, k, i, ¤tRightLimit, ¤tLeftLimit); vector<Formula*>& underscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentMainSymbol->right(), currentMainSymbol->left(), maxBottomLimit, currentMainSymbol->bottom() + 1, false); vector<Formula*>& overscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentMainSymbol->right(), currentMainSymbol->left(), currentMainSymbol->top(), maxTopLimit, false); findSubformulaeSymbols(mainSymbols, otherSymbols, k, underscriptSymbols, overscriptSymbols, currentRightLimit, currentLeftLimit); Parser parser; Formula* underscript = parser.parse(underscriptSymbols); Formula* overscript = parser.parse(overscriptSymbols); Formula* newIteratorOp = new IteratorOp(currentMainSymbol, underscript, overscript); result.push_back(newIteratorOp); i++; } else { result.push_back(mainSymbols.at(k)); } } result.insert(result.end(), otherSymbols.begin(), otherSymbols.end()); sort(result.begin(), result.end(), Formula::BarHorizontalComparator()); return result; }
void IteratorOpParser::findSubformulaeSymbols(vector<Formula*>& mainSymbols, vector<Formula*>& otherSymbols, unsigned int currentMainIndex, vector<Formula*>& underscriptSymbols, vector<Formula*>& overscriptSymbols, long currentRightLimit, long currentLeftLimit) { unsigned int& k = currentMainIndex; Formula* currentMainSymbol = mainSymbols.at(k); if (underscriptSymbols.empty() && overscriptSymbols.empty()) { // caso in cui non ci sono underscript e overscript ma (forse) apici e pedici long currentMainMidline = currentMainSymbol->center().getY(); unsigned int j = 0; bool beforeCurrentRightLimit = true; while (j < otherSymbols.size() && beforeCurrentRightLimit) { if (otherSymbols.at(j)->left() >= currentRightLimit) { beforeCurrentRightLimit = false; } else { Formula* oth = otherSymbols.at(j); bool crossedByMidline = oth->top() < currentMainMidline && currentMainMidline < oth->bottom(); if (crossedByMidline) { mainSymbols.insert(mainSymbols.begin() + k + 1, oth); otherSymbols.erase(otherSymbols.begin() + j); currentRightLimit = oth->left(); } j++; } } currentLeftLimit = currentMainSymbol->right(); underscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentRightLimit, currentLeftLimit, maxBottomLimit, currentMainMidline, true); overscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentRightLimit, currentLeftLimit, currentMainMidline, maxTopLimit, true); } else { // l'underscript e l'overscript, che al momento contengono solo simboli allineati verticalmente col main, vengono estesi underscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentRightLimit, currentLeftLimit, maxBottomLimit, currentMainSymbol->bottom() + 1, true); overscriptSymbols = FormulaParserUtils::extractSymbolsWithinRange(otherSymbols, currentRightLimit, currentLeftLimit, currentMainSymbol->top() - 1, maxTopLimit, true); } }
Formula * FractionParser::_buildNumDen(Formula * fraction, vector<Formula*> &remainingSymbols, bool (FractionParser::*check)(Formula * fraction, Formula * f)) { vector<Formula *> numDem; vector<Formula *> other; vector<Formula *>::iterator it = remainingSymbols.begin(); while (it != remainingSymbols.end()) { Formula * f = *it; SvgPoint fracBar = fraction->getBarycenter(); if (!(*f == *fraction)) { if (f->right() < fraction->right() + pixelFracMargin && f->left() > fraction->left() - pixelFracMargin && (this->*check)(fraction, f)) { numDem.push_back(f); } else { other.push_back(f); } } it++; } if (numDem.size() != 0) { other.insert(other.end(), it, remainingSymbols.end()); remainingSymbols = other; Parser p; Formula * numFormula = p.parse(numDem); return numFormula; } else { return NULL; } }
void SubSupParser::findSubSup(Formula** subformulaToSet, Formula* currentOther, vector<Formula*>& allSymbols, vector<Formula*>& mainSymbols, vector<Formula*>& otherSymbols, unsigned int currentMainIndex, bool sup_notSub) { using namespace FormulaParserUtils; unsigned int& i = currentMainIndex; Formula* currentMain = mainSymbols.at(currentMainIndex); long mainVBar = currentMain->center().getY(); int currentLeftLimit = currentMain->left(); int currentRightLimit = (i == mainSymbols.size() - 1) ? maxRightLimit : mainSymbols.at(i + 1)->left() - 1; bool subformulaCondition; long subsup_bottomLimit, subsup_topLimit, context_bottomLimit, context_topLimit; if (sup_notSub) { //apice bool higherTop = currentOther->top() + currentOther->height() * SUP_MIN_FRACTION_ABOVE_MAIN < currentMain->top(); bool higherBar = getWeightedVBar(currentOther) < getWeightedVBar(currentMain) && currentOther->area() <= currentMain->area() * LOW_SUP_MAX_AREA; subformulaCondition = higherTop || higherBar; // /* un apice deve: // * - avere un bordo superiore "sufficientemente" più in alto del mainSymbol corrente, OPPURE // * - avere un baricentro più alto ed essere "sufficientemente" più piccolo del simbolo principale // * */ subsup_bottomLimit = mainVBar; subsup_topLimit = maxTopLimit; context_bottomLimit = maxBottomLimit; context_topLimit = mainVBar; } else { //pedice subformulaCondition = (currentOther->bottom() - currentOther->height() * SUB_MIN_FRACTION_BELOW_MAIN) > currentMain->bottom(); // // un pedice deve trovarsi "sufficientemente" più in basso del mainSymbol corrente subsup_bottomLimit = maxBottomLimit; subsup_topLimit = mainVBar; context_bottomLimit = mainVBar; context_topLimit = maxTopLimit; } if (!subformulaCondition) { /* Non vengono rispettate le condizioni date: l'apice/pedice è stato mal classificato. Viene allora aggiunto ai simboli principali ed eliminato * da quelli secondari. */ mainSymbols.insert(mainSymbols.begin() + i + 1, currentOther); otherSymbols.erase(otherSymbols.begin()); } else { otherSymbols.erase(otherSymbols.begin()); vector<Formula*> subsup = extractSymbolsInRange(otherSymbols, currentRightLimit, currentLeftLimit, subsup_bottomLimit, subsup_topLimit); subsup.insert(subsup.begin(), currentOther); /* Viene passato allSymbols e non otherSymbols perché gli elementi di otherSymbols vengono cancellati una volta classificati (quindi se classifico, * ad esempio, un pedice poi quei simboli non saranno più in otherSymbols e non verrebbero più trovati dalla funzione di estrazione, che quindi non * fornirebbe il contesto appropriato) */ vector<Formula*> context = extractSymbolsInRange(allSymbols, currentRightLimit, currentLeftLimit, context_bottomLimit, context_topLimit, false); fixBadClassification(mainSymbols, otherSymbols, subsup, context, i); *subformulaToSet = _parse(subsup, allSymbols); } }