Add break quality scoring

Implement aesthetic break point selection to prefer natural break locations
  (e.g., after operators) rather than arbitrary positions when line wrapping
  mathematical expressions.
This commit is contained in:
Nicolas Guillot
2025-11-14 12:23:27 +01:00
parent 4441528f46
commit ca0c3fbe07
3 changed files with 372 additions and 40 deletions

View File

@@ -337,19 +337,25 @@ The following cases that previously forced line breaks now work perfectly:
**Progress**: Scripted atoms now participate in interatom breaking decisions while preserving correct script positioning!
### Priority 1 (NEW): Implement Break Quality Scoring
**Goal**: Prefer better break points (e.g., after operators).
### Break Quality Scoring (NEWLY COMPLETED!)
**Goal**: Prefer better break points aesthetically (e.g., after operators rather than in the middle of expressions).
**Approach**:
1. Assign penalty scores to different break point types
2. When projected width slightly exceeds maxWidth, look ahead 1-3 atoms
3. Choose break point with lowest penalty within acceptable width range
**Implementation**: Lines 517-607 in MTTypesetter.swift
- Added `calculateBreakPenalty()` function that assigns penalty scores:
* Penalty 0 (best): After binary operators (+, -, ×, ÷), relations (=, <, >), punctuation
* Penalty 10 (good): After ordinary atoms (variables, numbers)
* Penalty 100 (bad): After open brackets or before close brackets
* Penalty 150 (worse): After unary/large operators
- Modified `checkAndPerformInteratomLineBreak()` with look-ahead logic:
* When width is slightly exceeded (100%-120% of maxWidth), looks ahead up to 3 atoms
* Calculates penalties for each potential break point in window
* Chooses break point with lowest penalty
* Defers breaking if better point found within look-ahead window
- Updated to handle special atom types (Space, Style) that don't participate in width calculations
**Implementation**: Add `calculateBreakPenalty()` method, modify `checkAndPerformInteratomLineBreak()`.
**Impact**: ⭐⭐⭐⭐ SIGNIFICANT aesthetic improvement! Expressions now break at natural, readable points!
**Impact**: ⭐⭐⭐ (Nice aesthetic improvement)
**Difficulty**: Medium (new algorithm but well-defined pattern)
**Progress**: COMPLETED with 8 comprehensive tests!
### Priority 2: Dynamic Line Height
**Goal**: Adjust vertical spacing based on actual line content height.
@@ -394,9 +400,10 @@ The following cases that previously forced line breaks now work perfectly:
**Real-world examples** (NEW - 3 tests in lines 2417-2492)
**Edge cases** (NEW - 2 tests in lines 2494-2534)
**Scripted atoms inline** (NEW - 8 tests in lines 2609-2780)
**Break quality scoring** (NEW - 8 tests in lines 2797-3006)
**Total: 81 tests in MTTypesetterTests.swift, all passing on iOS**
**Overall: 232 tests across entire test suite, all passing**
**Total: 89 tests in MTTypesetterTests.swift, all passing on iOS**
**Overall: 240 tests across entire test suite, all passing**
### Coverage Summary by Category
@@ -409,7 +416,7 @@ The following cases that previously forced line breaks now work perfectly:
- Real-world: 3 tests (quadratic formula with color, complex fractions, mixed operations)
- Edge cases: 2 tests (very narrow width, very wide atom)
**Improved Script Handling:** (8 NEW tests)
**Improved Script Handling:** (8 tests)
- Scripted atoms inline when fit
- Scripted atoms break when too wide
- Mixed scripted and non-scripted atoms
@@ -419,6 +426,16 @@ The following cases that previously forced line breaks now work perfectly:
- No breaking without width constraint
- Complex expressions mixing fractions and scripts
**Break Quality Scoring:** (8 NEW tests)
- Prefer breaking after binary operators (+, -, ×, ÷)
- Prefer breaking after relation operators (=, <, >)
- Avoid breaking after open brackets
- Look-ahead finds better break points
- Multiple operators break at best available points
- Complex expressions with various atom types
- No unnecessary breaks when content fits
- Penalty ordering validates break preferences
**Edge Cases & Stress Tests:** (4 tests)
- Very narrow widths (30pt)
- Very wide atoms (overflow)
@@ -480,16 +497,13 @@ The implementation now provides **excellent support** for:
**Still need work** for:
- ⚠️ Very long text atoms - break within atom rather than between atoms
- ⚠️ Break quality scoring - all break points treated equally (no preference for breaking after operators)
- ⚠️ Dynamic line height - fixed spacing regardless of content height
**Note**: These are aesthetic improvements rather than fundamental limitations!
**Note**: These are minor aesthetic improvements rather than fundamental limitations!
### 🎯 Next Priorities
### 🎯 Next Priority
The most impactful remaining improvements:
1. **Add break quality scoring** (Priority 1) - prefer better break points aesthetically
2. **Dynamic line height** (Priority 2) - adjust vertical spacing based on content height
3. **Look-ahead optimization** (Priority 3) - consider slightly better break points nearby
The most impactful remaining improvement:
1. **Dynamic line height** (Priority 1) - adjust vertical spacing based on actual content height rather than fixed fontSize × 1.5
**Progress**: 🎉 **100% complete for all atom types!** All major atom types (simple, complex, and scripted) now support intelligent inline layout with width-based breaking!
**Progress**: 🎉 **100% complete for all atom types + intelligent break point selection!** All major atom types (simple, complex, and scripted) now support intelligent inline layout with width-based breaking AND aesthetically-pleasing break point selection!