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);
        }
Example #2
0
        /// <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)));
        }
Example #5
0
        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)));
        }