private PdfRectangle GetBoundingBoxOther(IReadOnlyList <TextLine> lines) { var points = lines.SelectMany(l => new[] { l.BoundingBox.BottomLeft, l.BoundingBox.BottomRight, l.BoundingBox.TopLeft, l.BoundingBox.TopRight }); // Candidates bounding boxes var obb = Geometry.GeometryExtensions.MinimumAreaRectangle(points); var obb1 = new PdfRectangle(obb.BottomLeft, obb.TopLeft, obb.BottomRight, obb.TopRight); var obb2 = new PdfRectangle(obb.BottomRight, obb.BottomLeft, obb.TopRight, obb.TopLeft); var obb3 = new PdfRectangle(obb.TopRight, obb.BottomRight, obb.TopLeft, obb.BottomLeft); // Find the orientation of the OBB, using the baseline angle // Assumes line order is correct var lastLine = lines[lines.Count - 1]; var baseLineAngle = Distances.BoundAngle180(Distances.Angle(lastLine.BoundingBox.BottomLeft, lastLine.BoundingBox.BottomRight)); double deltaAngle = Math.Abs(Distances.BoundAngle180(obb.Rotation - baseLineAngle)); double deltaAngle1 = Math.Abs(Distances.BoundAngle180(obb1.Rotation - baseLineAngle)); if (deltaAngle1 < deltaAngle) { deltaAngle = deltaAngle1; obb = obb1; } double deltaAngle2 = Math.Abs(Distances.BoundAngle180(obb2.Rotation - baseLineAngle)); if (deltaAngle2 < deltaAngle) { deltaAngle = deltaAngle2; obb = obb2; } double deltaAngle3 = Math.Abs(Distances.BoundAngle180(obb3.Rotation - baseLineAngle)); if (deltaAngle3 < deltaAngle) { obb = obb3; } return(obb); }
private static PdfRectangle GetBoundingBoxOther(IReadOnlyList <Word> words) { var baseLinePoints = words.SelectMany(r => new[] { r.BoundingBox.BottomLeft, r.BoundingBox.BottomRight, }).ToList(); // Fitting a line through the base lines points // to find the orientation (slope) double x0 = baseLinePoints.Average(p => p.X); double y0 = baseLinePoints.Average(p => p.Y); double sumProduct = 0; double sumDiffSquaredX = 0; for (int i = 0; i < baseLinePoints.Count; i++) { var point = baseLinePoints[i]; var x_diff = point.X - x0; var y_diff = point.Y - y0; sumProduct += x_diff * y_diff; sumDiffSquaredX += x_diff * x_diff; } double cos = 0; double sin = 1; if (sumDiffSquaredX > 1e-3) { // not a vertical line double angleRad = Math.Atan(sumProduct / sumDiffSquaredX); // -π/2 ≤ θ ≤ π/2 cos = Math.Cos(angleRad); sin = Math.Sin(angleRad); } // Rotate the points to build the axis-aligned bounding box (AABB) var inverseRotation = new TransformationMatrix( cos, -sin, 0, sin, cos, 0, 0, 0, 1); var transformedPoints = words.SelectMany(r => new[] { r.BoundingBox.BottomLeft, r.BoundingBox.BottomRight, r.BoundingBox.TopLeft, r.BoundingBox.TopRight }).Distinct().Select(p => inverseRotation.Transform(p)); var aabb = new PdfRectangle(transformedPoints.Min(p => p.X), transformedPoints.Min(p => p.Y), transformedPoints.Max(p => p.X), transformedPoints.Max(p => p.Y)); // Rotate back the AABB to obtain to oriented bounding box (OBB) var rotateBack = new TransformationMatrix( cos, sin, 0, -sin, cos, 0, 0, 0, 1); // Candidates bounding boxes var obb = rotateBack.Transform(aabb); var obb1 = new PdfRectangle(obb.BottomLeft, obb.TopLeft, obb.BottomRight, obb.TopRight); var obb2 = new PdfRectangle(obb.BottomRight, obb.BottomLeft, obb.TopRight, obb.TopLeft); var obb3 = new PdfRectangle(obb.TopRight, obb.BottomRight, obb.TopLeft, obb.BottomLeft); // Find the orientation of the OBB, using the baseline angle // Assumes word order is correct var firstWord = words[0]; var lastWord = words[words.Count - 1]; var baseLineAngle = Distances.Angle(firstWord.BoundingBox.BottomLeft, lastWord.BoundingBox.BottomRight); double deltaAngle = Math.Abs(Distances.BoundAngle180(obb.Rotation - baseLineAngle)); double deltaAngle1 = Math.Abs(Distances.BoundAngle180(obb1.Rotation - baseLineAngle)); if (deltaAngle1 < deltaAngle) { deltaAngle = deltaAngle1; obb = obb1; } double deltaAngle2 = Math.Abs(Distances.BoundAngle180(obb2.Rotation - baseLineAngle)); if (deltaAngle2 < deltaAngle) { deltaAngle = deltaAngle2; obb = obb2; } double deltaAngle3 = Math.Abs(Distances.BoundAngle180(obb3.Rotation - baseLineAngle)); if (deltaAngle3 < deltaAngle) { obb = obb3; } return(obb); }