// add a word break (possibly for a hyphenated fragment), and add desperate // breaks if needed (ie when word exceeds current line width) void LineBreaker::addWordBreak(size_t offset, ParaWidth preBreak, ParaWidth postBreak, size_t preSpaceCount, size_t postSpaceCount, float penalty, HyphenationType hyph) { Candidate cand; ParaWidth width = mCandidates.back().preBreak; if (postBreak - width > currentLineWidth()) { // Add desperate breaks. // Note: these breaks are based on the shaping of the (non-broken) original // text; they are imprecise especially in the presence of kerning, // ligatures, and Arabic shaping. size_t i = mCandidates.back().offset; width += mCharWidths[i++]; for (; i < offset; i++) { float w = mCharWidths[i]; if (w > 0) { cand.offset = i; cand.preBreak = width; cand.postBreak = width; // postSpaceCount doesn't include trailing spaces cand.preSpaceCount = postSpaceCount; cand.postSpaceCount = postSpaceCount; cand.penalty = SCORE_DESPERATE; cand.hyphenType = HyphenationType::BREAK_AND_DONT_INSERT_HYPHEN; #if VERBOSE_DEBUG ALOGD("desperate cand: %zd %g:%g", mCandidates.size(), cand.postBreak, cand.preBreak); #endif addCandidate(cand); width += w; } } } cand.offset = offset; cand.preBreak = preBreak; cand.postBreak = postBreak; cand.penalty = penalty; cand.preSpaceCount = preSpaceCount; cand.postSpaceCount = postSpaceCount; cand.hyphenType = hyph; #if VERBOSE_DEBUG ALOGD("cand: %zd %g:%g", mCandidates.size(), cand.postBreak, cand.preBreak); #endif addCandidate(cand); }
void R2RegionCoverer::getCovering( const R2Region& region, vector<GeoHash>* cover ) { // Strategy: Start with the full plane. Discard any // that do not intersect the shape. Then repeatedly choose the // largest cell that intersects the shape and subdivide it. // // _result contains the cells that will be part of the output, while the // queue contains cells that we may still subdivide further. Cells that // are entirely contained within the region are immediately added to the // output, while cells that do not intersect the region are immediately // discarded. Therefore the queue only contains cells that partially // intersect the region. Candidates are prioritized first according to // cell size (larger cells first), then by the number of intersecting // children they have (fewest children first), and then by the number of // fully contained children (fewest children first). verify(_minLevel <= _maxLevel); dassert(_candidateQueue->empty()); dassert(_results->empty()); _region = ®ion; getInitialCandidates(); while(!_candidateQueue->empty()) { Candidate* candidate = _candidateQueue->top().second; // Owned _candidateQueue->pop(); LOG(3) << "Pop: " << candidate->cell; // Try to expand this cell into its children if (candidate->cell.getBits() < _minLevel || candidate->numChildren == 1 || (int)_results->size() + (int)_candidateQueue->size() + candidate->numChildren <= _maxCells) { for (int i = 0; i < candidate->numChildren; i++) { addCandidate(candidate->children[i]); } deleteCandidate(candidate, false); } else { // Reached max cells. Move all candidates from the queue into results. candidate->isTerminal = true; addCandidate(candidate); } LOG(3) << "Queue: " << _candidateQueue->size(); } _region = NULL; cover->swap(*_results); }
static void fillSurfaceWeightPattern (OTGrammarTableau me, long numberOfSyllables, int stress [], int footedToTheLeft [], int footedToTheRight [], int underlyingWeightPattern [], int overtFormsHaveSecondaryStress) { int surfaceWeightPattern [1+7], minSurfaceWeight [1+7], maxSurfaceWeight [1+7]; int weight1, weight2, weight3, weight4, weight5; for (long isyll = 1; isyll <= numberOfSyllables; isyll ++) { if (underlyingWeightPattern [isyll] < 3) { minSurfaceWeight [isyll] = maxSurfaceWeight [isyll] = underlyingWeightPattern [isyll]; /* L -> L; H -> H */ } else { minSurfaceWeight [isyll] = 3, maxSurfaceWeight [isyll] = 4; /* C -> { J, K } */ } } surfaceWeightPattern [6] = surfaceWeightPattern [7] = 1; /* Constant L. */ for (weight1 = minSurfaceWeight [1]; weight1 <= maxSurfaceWeight [1]; weight1 ++) { surfaceWeightPattern [1] = weight1; for (weight2 = minSurfaceWeight [2]; weight2 <= maxSurfaceWeight [2]; weight2 ++) { surfaceWeightPattern [2] = weight2; if (numberOfSyllables == 2) { addCandidate (me, 2, stress, footedToTheLeft, footedToTheRight, surfaceWeightPattern, overtFormsHaveSecondaryStress); } else for (weight3 = minSurfaceWeight [3]; weight3 <= maxSurfaceWeight [3]; weight3 ++) { surfaceWeightPattern [3] = weight3; if (numberOfSyllables == 3) { addCandidate (me, 3, stress, footedToTheLeft, footedToTheRight, surfaceWeightPattern, overtFormsHaveSecondaryStress); } else for (weight4 = minSurfaceWeight [4]; weight4 <= maxSurfaceWeight [4]; weight4 ++) { surfaceWeightPattern [4] = weight4; if (numberOfSyllables == 4) { addCandidate (me, 4, stress, footedToTheLeft, footedToTheRight, surfaceWeightPattern, overtFormsHaveSecondaryStress); } else for (weight5 = minSurfaceWeight [5]; weight5 <= maxSurfaceWeight [5]; weight5 ++) { surfaceWeightPattern [5] = weight5; addCandidate (me, numberOfSyllables, stress, footedToTheLeft, footedToTheRight, surfaceWeightPattern, overtFormsHaveSecondaryStress); } } } } } }
// Takes ownership of "candidate" void R2RegionCoverer::addCandidate( Candidate* candidate ) { if (candidate == NULL) return; if (candidate->isTerminal) { _results->push_back(candidate->cell); deleteCandidate(candidate, true); return; } verify(candidate->numChildren == 0); // Expand children int numTerminals = expandChildren(candidate); if (candidate->numChildren == 0) { deleteCandidate(candidate, true); } else if (numTerminals == 4 && candidate->cell.getBits() >= _minLevel) { // Optimization: add the parent cell rather than all of its children. candidate->isTerminal = true; addCandidate(candidate); } else { // Add the cell into the priority queue for further subdivision. // // We negate the priority so that smaller absolute priorities are returned // first. The heuristic is designed to refine the largest cells first, // since those are where we have the largest potential gain. Among cells // at the same level, we prefer the cells with the smallest number of // intersecting children. Finally, we prefer cells that have the smallest // number of children that cannot be refined any further. int priority = -((((candidate->cell.getBits() << 4) + candidate->numChildren) << 4) + numTerminals); _candidateQueue->push(make_pair(priority, candidate)); // queue owns candidate LOG(3) << "Push: " << candidate->cell << " (" << priority << ") "; } }
void R2RegionCoverer::getInitialCandidates() { // Add the full plane // TODO a better initialization. addCandidate(newCandidate(GeoHash())); }
// for merging candidate sets: CandidateSet& CandidateSet::operator+=(const CandidateSet& rhs) { for (int i=0; i < rhs.getSize(); ++i) { addCandidate(rhs[i]); } return *this; }