19 lines
1.3 KiB
TypeScript
19 lines
1.3 KiB
TypeScript
export type Box=[number,number,number,number];
|
|
export type TextRegion={box:Box;direction:string};
|
|
/** Associate residual glyphs with an existing semantic word/paragraph, never create a second word ID. */
|
|
export function textMergeTarget(fragment:Box,regions:TextRegion[]):number{
|
|
const[x,y,w,h]=fragment;let result=-1,best=Infinity;
|
|
for(const[index,r]of regions.entries()){
|
|
const[a,b,c,d]=r.box,vertical=r.direction==='vertical';
|
|
const gapX=Math.max(a-x-w,x-a-c,0),gapY=Math.max(b-y-h,y-b-d,0);
|
|
const overlapX=Math.max(0,Math.min(x+w,a+c)-Math.max(x,a)),overlapY=Math.max(0,Math.min(y+h,b+d)-Math.max(y,b));
|
|
const sameBaseline=overlapY/Math.max(1,Math.min(h,d))>=.55&&gapX<=Math.max(3,Math.min(7,d*.4));
|
|
const sameColumn=overlapX/Math.max(1,Math.min(w,c))>=.55&&gapY<=Math.max(2,Math.min(4,vertical?c*.3:2));
|
|
if(!(sameBaseline||sameColumn))continue;
|
|
// Nearby small footer blocks remain independent when the fragment has no baseline/column affinity.
|
|
const score=gapX+gapY+(vertical?(1-overlapX/Math.max(1,Math.min(w,c))):(1-overlapY/Math.max(1,Math.min(h,d))));
|
|
if(score<best){result=index;best=score}
|
|
}return result;
|
|
}
|
|
export function unionBoxes(a:Box,b:Box):Box{const x=Math.min(a[0],b[0]),y=Math.min(a[1],b[1]);return[x,y,Math.max(a[0]+a[2],b[0]+b[2])-x,Math.max(a[1]+a[3],b[1]+b[3])-y]}
|