private static BoundingBox DeskewBoundingBoxBase(BoundingBox src, IsometricTransform transform) { var cosAngle = Math.Abs(transform.CosAngle); var sinAngle = Math.Abs(transform.SinAngle); if (cosAngle > sinAngle) { var tmp = sinAngle; sinAngle = cosAngle; cosAngle = tmp; } var cos2Angle = cosAngle * cosAngle - sinAngle * sinAngle; var sin2Angle = 2 * sinAngle * cosAngle; var points = new List <Point> { transform.Transform(new Point(src.XMin, src.YMin)), transform.Transform(new Point(src.XMin, src.YMax)), transform.Transform(new Point(src.XMax, src.YMax)), transform.Transform(new Point(src.XMax, src.YMin)), }; var xMin = points.Select(point => point.x).Min(); var xMax = points.Select(point => point.x).Max(); var yMin = points.Select(point => point.y).Min(); var yMax = points.Select(point => point.y).Max(); var W = xMax - xMin; var H = yMax - yMin; var p = ((W * sin2Angle - H) * sin2Angle) / ((sin2Angle * sin2Angle - 1) * 2); var q = ((H * sin2Angle - W) * sin2Angle) / ((sin2Angle * sin2Angle - 1) * 2); // var p = 0; // var q = 0; var result = new BoundingBox(Floor(xMin + p), Floor(yMin + q), Ceiling(xMax - p), Ceiling(yMax - q)); // Console.Out.WriteLine(@"""{0}"": ({1}) => ({2})", word.Text, src, result); // if (word.Text == "Óòâåðæäåíà") // { // Console.Out.WriteLine("Òðàíñôîðìàöèÿ:"); // Console.Out.WriteLine("xMin: {0:N4}", xMin); // Console.Out.WriteLine("xMax: {0:N4}", xMax); // Console.Out.WriteLine("yMin: {0:N4}", yMin); // Console.Out.WriteLine("yMax: {0:N4}", yMax); // Console.Out.WriteLine("W: {0:N4}", W); // Console.Out.WriteLine("H: {0:N4}", H); // Console.Out.WriteLine("p: {0:N4}", p); // Console.Out.WriteLine("q: {0:N4}", q); // Console.Out.WriteLine("result: {0}", result); // Console.Out.WriteLine("cosAngle: {0:N4}", cosAngle); // Console.Out.WriteLine("sinAngle: {0:N4}", sinAngle); // Console.Out.WriteLine("cos2angle: {0:N4}", cos2Angle); // Console.Out.WriteLine("sin2angle: {0:N4}", sin2Angle); // foreach (var point in points) // { // Console.Out.WriteLine(point); // } // Console.Out.WriteLine(@"""{0}"": ({1}) => ({2})", word.Text, src, result); // } return(result); }
/// <summary> /// Calculates composition of two transformations, i.e. new transformation C(x) = A(B(x)) /// </summary> /// <param name="trA"></param> /// <param name="trB"></param> /// <returns></returns> public static IsometricTransform Compose(IsometricTransform trA, IsometricTransform trB) { var newAngle = Angles.NormalizeRad(trA.AngleRadians + trB.AngleRadians); var newPreShift = new Point(trB.preShiftX, trB.preShiftY); var newPostShift = trA.Transform(new Point(trB.postShiftX, trB.postShiftY)); return(new IsometricTransform(newAngle, newPostShift, newPreShift)); }
/// <summary> /// Rotates given model by given isomorphic transform. /// Bounding box for an object of the model is transformed in such a way that it is still the minimal rectangle with sides parallel to coordinate axes contaning original box rotated. /// </summary> /// <param name="model">The model to process</param> /// <param name="transform">The transform to apply</param> /// <param name="targetWidth">Target model width</param> /// <param name="targetHeight">Target model height</param> /// <returns></returns> public static TextGeometryModel RotateModel(this TextGeometryModel model, IsometricTransform transform, int targetWidth, int targetHeight) { var targetModel = new TextGeometryModel(new BoundingBox(0, 0, targetWidth, targetHeight), model.GridUnit); ModelGeometryTransformer.TransformModelGeometry(model, targetModel, box => RotateBoundingBox(box, transform)); return(targetModel); }
private static BoundingBox RotateBoundingBox(BoundingBox src, IsometricTransform transform) { var points = new List <Point> { transform.Transform(new Point(src.XMin, src.YMin)), transform.Transform(new Point(src.XMin, src.YMax)), transform.Transform(new Point(src.XMax, src.YMax)), transform.Transform(new Point(src.XMax, src.YMin)), }; var xMin = points.Select(point => point.x).Min(); var xMax = points.Select(point => point.x).Max(); var yMin = points.Select(point => point.y).Min(); var yMax = points.Select(point => point.y).Max(); return(new BoundingBox(Floor(xMin), Floor(yMin), Ceiling(xMax), Ceiling(yMax))); }
private void CalculateTransformationParams() { var rotation = new IsometricTransform(angleRadians, 0, 0, 0, 0); var points = new List <Point> { rotation.Transform(new Point(0, 0)), rotation.Transform(new Point(0, sourceHeight)), rotation.Transform(new Point(sourceWidth, 0)), rotation.Transform(new Point(sourceWidth, sourceHeight)) }; var maxX = points.Select(point => point.x).Max(); var minX = points.Select(point => point.x).Min(); var maxY = points.Select(point => point.y).Max(); var minY = points.Select(point => point.y).Min(); transform = new IsometricTransform(angleRadians, -minX, -minY, 0, 0); targetWidth = (int)Math.Round(maxX - minX); targetHeight = (int)Math.Round(maxY - minY); }
private static BoundingBox DeskewBoundingBox(BoundingBox src, IsometricTransform transform) { var cosAngle = Math.Abs(transform.CosAngle); var sinAngle = Math.Abs(transform.SinAngle); if (cosAngle > sinAngle) { var tmp = sinAngle; sinAngle = cosAngle; cosAngle = tmp; } var sin2Angle = 2 * sinAngle * cosAngle; var sin2AngleSq = sin2Angle * sin2Angle; var cos2AngleSq = 1 - sin2AngleSq; var points = new List <Point> { transform.Transform(new Point(src.XMin, src.YMin)), transform.Transform(new Point(src.XMin, src.YMax)), transform.Transform(new Point(src.XMax, src.YMax)), transform.Transform(new Point(src.XMax, src.YMin)), }; var xMin = points.Select(point => point.x).Min(); var xMax = points.Select(point => point.x).Max(); var yMin = points.Select(point => point.y).Min(); var yMax = points.Select(point => point.y).Max(); // Here we have a rectangle that is a bounding one for original bounding rectangle rotated // The problem here is that this rectangle is not the bounding one for the word itself (due to rotation) // so we have to updte it (if possible) to reduce its size var W = xMax - xMin; var H = yMax - yMin; var xCnt = (xMin + xMax) / 2; var yCnt = (yMin + yMax) / 2; var w = (W - sin2Angle * H) / cos2AngleSq; var h = (H - sin2Angle * W) / cos2AngleSq; // According to formulas, values of w and h should be positive // but under some circumstances (line contains words in fonts of different sizes) they can become negative (as desckew formulas // are obtained under assumption that line contains words of the same vertical size). So in this case we just make the values non-negative // (although the result will not be quite good - according to the resulting sizes words will be higher than the line itself) w = Math.Abs(w); h = Math.Abs(h); // New height and width are suitable for the case when rotation angle was chosen correctly to deskew the model // (i.e. the words have been aligned horizontally). Unfortunately, the can be the cases when the angle is a wrong one // and words are not aligned properly. In such cases we have to limit new bounding rectangle dimensions by the ones obtained // by rotation of original bounding rectangle (without any correction). Otherwise there is a risk that new bounding rectangle // will lay outside of the page (and its coordinates get negative) if (w > W) { w = W; } if (h > H) { h = H; } var w2 = w / 2; var h2 = h / 2; return(new BoundingBox(Floor(xCnt - w2), Floor(yCnt - h2), Ceiling(xCnt + w2), Ceiling(yCnt + h2))); }