예제 #1
0
        /// <summary>
        /// TODO: LDPoint注意
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="clip"></param>
        /// <returns></returns>
        public LDPoint inverseTransform(LDPoint pt, bool clip = false)
        {
            if (getColumn() == 0 && getRow() == 0)
            {
                //メッシュがない場合はそのままの値を返す
                return(pt);
            }

            double x = pt.x();
            double y = pt.y();


            //Gridからマッピング先のQuadを見つける
            LDPoint index = getMapedQuadIndex(new LDPoint((float)x, (float)y));
            int     col   = (int)index.x();
            int     row   = (int)index.y();

            if (clip)
            {
                //Grid内にClipする。QuadをClipして変換するのではない
                col = LDMathUtil.clamp(col, 0, getColumn());
                row = LDMathUtil.clamp(row, 0, getRow());
            }

            LDPoint local = new LDPoint();

            if (isOutside(row, col))
            {
                LDQuadTransform quad = createOutsideQuadTransform(row, col);
                return(quad.inverseTransform(pt, clip));

                //TODO:到達しない場所あります
                local = quad.inverseTransform(pt, clip);

                LDPoint _internal = new LDPoint();
                _internal.setX((col + 1) * (1.0f / (getColumn() + 2)) + local.x() / (getColumn() + 2));
                _internal.setY((row + 1) * (1.0f / (getRow() + 2)) + local.y() / (getRow() + 2));

                LDQuadTransform tmp = new LDQuadTransform(new LDPoint(-1, -1), new LDPoint(getColumn() + 1, getRow() + 1));
                return(tmp.transform(_internal));
            }
            else
            {
                LDQuadTransform quad = getQuadTransform(row, col);
                local = quad.inverseTransform(pt, clip);

                LDPoint _internal = new LDPoint();
                _internal.setX(col * (1.0f / getColumn()) + local.x() / getColumn());
                _internal.setY(row * (1.0f / getRow()) + local.y() / getRow());

                return(_internal);
            }
        }
예제 #2
0
        public void wrapPiTest()
        {
            ld_float actual;
            ld_float expected;
            ld_float theta;

            //ld_float delta = 0.00001f;

            // Input : 0.0
            theta    = 0.0f;
            expected = 0.0f;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            // Input : 2PI
            theta    = LDMathUtil.PI2;
            expected = 0.0f;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            // Input : PI, PI±0.01におけるラップテスト
            theta    = LDMathUtil.PI - 0.01f;
            expected = LDMathUtil.PI - 0.01f;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            theta    = LDMathUtil.PI;
            expected = LDMathUtil.PI;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            theta    = LDMathUtil.PI + 0.01f;
            expected = 0.01f - LDMathUtil.PI;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            // Input : -PI, -PI±0.01におけるラップテスト
            theta    = -LDMathUtil.PI - 0.01f;
            expected = LDMathUtil.PI - 0.01f;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            theta    = -LDMathUtil.PI;
            expected = -LDMathUtil.PI;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);

            theta    = -LDMathUtil.PI + 0.01f;
            expected = -LDMathUtil.PI + 0.01f;
            actual   = LDMathUtil.wrapPi(theta);
            TestUtil.COMPARE(expected, actual);
        }
예제 #3
0
        /**
         * @brief 慣性空間->オブジェクト空間への回転
         * @param &orientation オイラー角(EEulerAngles)をセットする
         */
        void setToRotateInertialToObject(LDEulerAngles orientation)
        {
            ld_float sp, sb, sh;
            ld_float cp, cb, ch;

            LDMathUtil.sinCos(out sp, out cp, orientation.pitch * 0.5f);
            LDMathUtil.sinCos(out sb, out cb, orientation.bank * 0.5f);
            LDMathUtil.sinCos(out sh, out ch, orientation.heading * 0.5f);

            w = ch * cp * cb + sh * sp * sb;
            x = -ch * sp * cb - sh * cp * sb;
            y = ch * sp * sb - sh * cp * cb;
            z = sh * sp * cb - ch * cp * sb;
        }
예제 #4
0
파일: LDUvMesh.cs 프로젝트: johndpope/math
        public void updateUvMap(LDSize ImageSize)
        {
            m_uvMap.Clear();
            for (int i = 0; i < m_points.size(); i++)
            {
                float u = m_points[i].x() / ImageSize.width();
                float v = m_points[i].y() / ImageSize.height();

                LDMathUtil.clamp(u, 0.0f, 1.0f);
                LDMathUtil.clamp(v, 0.0f, 1.0f);

                m_uvMap.Add(new LDPoint(u, v));
            }
        }
예제 #5
0
파일: LDUvMesh.cs 프로젝트: johndpope/math
        //追加。UV経由での追加しかできない。Positionは自動で計算される
        public void addUv(LDPoint uv, bool clamp = true)
        {
            if (clamp)
            {
                //0-1区間の縛りに引っかかる処理が多いので、デフォルトでは自動で直す
                uv = LDMathUtil.clamp(uv, new LDPoint(0, 0), new LDPoint(1, 1));
            }
            else
            {
                common.LD_ASSERT_OUT_OF_RANGE(uv.x(), 0, 1);
                common.LD_ASSERT_OUT_OF_RANGE(uv.y(), 0, 1);
            }


            m_uvMap.Add(uv);
            //頂点の計算
            m_points.Add(getCalcAddVertex(uv));
        }
예제 #6
0
        public void getAngleDiffTest()
        {
            ld_float actual;
            ld_float expected;
            ld_float Q1, Q2;

            //ld_float delta = 0.00001f;

            // Input : Q1 = 0.0, Q2 = 0.0
            Q1       = 0.0f;
            Q2       = 0.0f;
            expected = 0.0f;
            actual   = LDMathUtil.getAngleDiff(Q1, Q2);
            TestUtil.COMPARE(expected, actual);

            // Input : Q1 = PI, Q2 = 0.0
            Q1       = LDMathUtil.PI;
            Q2       = 0.0f;
            expected = LDMathUtil.PI;
            actual   = LDMathUtil.getAngleDiff(Q1, Q2);
            TestUtil.COMPARE(expected, actual);

            // Input : Q1 = PI+0.1, Q2 = 0.0
            Q1       = LDMathUtil.PI + 0.1f;
            Q2       = 0.0f;
            expected = -LDMathUtil.PI + 0.1f;
            actual   = LDMathUtil.getAngleDiff(Q1, Q2);
            TestUtil.COMPARE(expected, actual);

            // Input : Q1 = -PI, Q2 = 0.0
            Q1       = -LDMathUtil.PI;
            Q2       = 0.0f;
            expected = -LDMathUtil.PI;
            actual   = LDMathUtil.getAngleDiff(Q1, Q2);
            TestUtil.COMPARE(expected, actual);

            // Input : Q1 = -PI-0.1, Q2 = 0.0
            Q1       = -LDMathUtil.PI - 0.1f;
            Q2       = 0.0f;
            expected = LDMathUtil.PI - 0.1f;
            actual   = LDMathUtil.getAngleDiff(Q1, Q2);
            TestUtil.COMPARE(expected, actual);
        }
예제 #7
0
        public void safeAcosTest()
        {
            ld_float actual;
            ld_float expected;
            ld_float x;

            //ld_float delta = 0.00001f;

            // Input : x = -1.0f
            x        = -1.0f;
            expected = LDMathUtil.PI;
            actual   = LDMathUtil.safeAcos(x);
            TestUtil.COMPARE(expected, actual);

            // Input : x = 1.0f
            x        = 1.0f;
            expected = 0.0f;
            actual   = LDMathUtil.safeAcos(x);
            TestUtil.COMPARE(expected, actual);
        }
예제 #8
0
        public LDPoint transform(double tx, double ty, bool clip = false)
        {
            if (clip)
            {
                tx = LDMathUtil.clamp(tx, 0.0, 1.0);
                ty = LDMathUtil.clamp(ty, 0.0, 1.0);
            }

            /*
             *  if ( tx + ty < 1 )
             *  {
             *      //左上三角
             *      LDTriangleTransform tr(m_topLeft,m_topRight,m_bottomLeft);
             *      return tr.transform(tx,ty);
             *  }
             *  else
             *  {
             *      //右下三角
             *      //TODO SDKでは計算式を(1-t)にしている。違いがある?
             * //		LDTriangleTransform tr(m_bottomLeft,m_bottomRight,m_topRight);
             * //		return tr.transform(tx,ty);
             *      LDTriangleTransform tr(m_topRight,m_bottomLeft,m_bottomRight);
             *      return tr.transformOneMinusT(tx,ty);
             *  }
             */

            double x = LDMathUtil.lerp2D(
                m_topLeft.x(), m_topRight.x(), tx,
                m_bottomLeft.x(), m_bottomRight.x(), ty
                );
            double y = LDMathUtil.lerp2D(
                m_topLeft.y(), m_topRight.y(), tx,
                m_bottomLeft.y(), m_bottomRight.y(), ty
                );

            return(new LDPoint((float)x, (float)y));
        }
예제 #9
0
        public LDPoint inverseTransform(double x, double y, bool clip = false)
        {
            /*
             *  QPolygonF p;
             *  p.Add(m_topLeft);
             *  p.Add(m_topRight);
             *  p.Add(m_bottomLeft);
             * //	p<<m_topLeft<<m_topRight<<m_bottomLeft;
             *
             *  if ( p.containsPoint(LDPoint(x,y),Qt.WindingFill))
             *  {
             *      //左上三角
             *      LDTriangleTransform tr(m_topLeft,m_topRight,m_bottomLeft);
             *      return tr.inverseTransform(x,y);
             *  }
             *  else
             *  {
             *      //右下三角
             *      //TODO SDKでは計算式を(1-t)にしている。違いがある?
             * //		LDTriangleTransform tr(m_bottomLeft,m_bottomRight,m_topRight);
             * //		return tr.transform(tx,ty);
             *      LDTriangleTransform tr(m_topRight,m_bottomLeft,m_bottomRight);
             *      return tr.inverseTransformOneMinusT(x,y);
             *  }
             */
            double tx, ty;

            LDMathUtil.inverseLerp2D(m_topLeft, m_topRight, m_bottomLeft, m_bottomRight, new LDPoint((float)x, (float)y), out tx, out ty);

            if (clip)
            {
                tx = LDMathUtil.clamp(tx, 0.0, 1.0);
                ty = LDMathUtil.clamp(ty, 0.0, 1.0);
            }

            return(new LDPoint((float)tx, (float)ty));
        }
예제 #10
0
        //平面上の点を変換した結果を返す。pは基本0..1の範囲
        /// <summary>
        /// TODO:LDPoint注意
        /// </summary>
        /// <param name="t"></param>
        /// <param name="clip"></param>
        /// <returns></returns>
        public LDPoint transform(LDPoint t, bool clip = false)
        {
            if (getColumn() == 0 && getRow() == 0)
            {
                //メッシュがない場合はそのままの値を返す
                return(t);
            }

            double tx = t.x();
            double ty = t.y();

            if (clip)
            {
                //Grid内にClipする。QuadをClipして変換するのではない
                tx = LDMathUtil.clamp(tx, 0.0, 1.0);
                ty = LDMathUtil.clamp(ty, 0.0, 1.0);
            }

            //Gridから対象のQuadを見つける
            LDPoint index = getQuadIndex(new LDPoint((float)tx, (float)ty));
            int     col   = (int)index.x();
            int     row   = (int)index.y();

            LDPoint local = getLocalPoint(new LDPoint((float)tx, (float)ty));

            if (isOutside(row, col))
            {
                LDQuadTransform quad = createOutsideQuadTransform(row, col);
                return(quad.transform(new LDPoint((float)tx, (float)ty)));
            }
            else
            {
                LDQuadTransform quad = getQuadTransform(row, col);
                return(quad.transform(local));
            }
        }
예제 #11
0
        //--------------------

        /**
         * @brief 回転角を取り出して返す
         */
        public ld_float getAngle()
        {
            return(LDMathUtil.safeAcos(w) * 2.0f);
        }
예제 #12
0
        public void mySlerpTest()
        {
            LDQuat quat1    = new LDQuat();
            LDQuat quat2    = new LDQuat();
            LDQuat actual   = new LDQuat();
            LDQuat expected = new LDQuat();
            //ld_float delta = 0.00001f;
            ld_float t;

            // Input : quat1{x = 1.0, y = 2.0, z = 3.0, w = 0.1}, quat2{x = 4.0, y = 5.0, z = 6.0, w = 0.2}, t = 0.0
            // 範囲外t <= 0.0fのケース
            quat1.x    = 1.0f;
            quat1.y    = 2.0f;
            quat1.z    = 3.0f;
            quat1.w    = 0.1f;
            quat2.x    = 4.0f;
            quat2.y    = 5.0f;
            quat2.z    = 6.0f;
            quat2.w    = 0.2f;
            t          = 0.0f;
            expected.x = 4.0f;
            expected.y = 5.0f;
            expected.z = 6.0f;
            expected.w = 0.2f;
            actual     = quat2.mySlerp(quat1, t);
            TestUtil.COMPARE(expected.x, actual.x);
            TestUtil.COMPARE(expected.y, actual.y);
            TestUtil.COMPARE(expected.z, actual.z);
            TestUtil.COMPARE(expected.w, actual.w);

            // Input : quat1{x = 1.0, y = 2.0, z = 3.0, w = 0.1}, quat2{x = 4.0, y = 5.0, z = 6.0, w = 0.2}, t = 1.0
            // 範囲外t >= 1.0fのケース
            quat1.x    = 1.0f;
            quat1.y    = 2.0f;
            quat1.z    = 3.0f;
            quat1.w    = 0.1f;
            quat2.x    = 4.0f;
            quat2.y    = 5.0f;
            quat2.z    = 6.0f;
            quat2.w    = 0.2f;
            t          = 1.0f;
            expected.x = 1.0f;
            expected.y = 2.0f;
            expected.z = 3.0f;
            expected.w = 0.1f;
            actual     = quat2.mySlerp(quat1, t);
            TestUtil.COMPARE(expected.x, actual.x);
            TestUtil.COMPARE(expected.y, actual.y);
            TestUtil.COMPARE(expected.z, actual.z);
            TestUtil.COMPARE(expected.w, actual.w);

            // Input : quat1{x = 0.49, y = 0.5, z = 0.5, w = 0.5}, quat2{x = 0.5, y = 0.49, z = 0.5, w = 0.5}, t = 0.5
            // cosOmega <= 0.9999fのケース
            quat1.x = 0.49f;
            quat1.y = 0.5f;
            quat1.z = 0.5f;
            quat1.w = 0.5f;
            quat2.x = 0.5f;
            quat2.y = 0.49f;
            quat2.z = 0.5f;
            quat2.w = 0.5f;
            t       = 0.5f;
            LDVector3 n0    = quat2.getAxis();
            LDVector3 n1    = quat1.getAxis();
            ld_float  a0    = quat2.getAngle();
            ld_float  a1    = quat1.getAngle();
            ld_float  adiff = LDMathUtil.getAngleDiff(a1, a0);
            ld_float  at    = a0 + adiff * t;
            LDVector3 nt    = LDVector3.blend(n0, n1, 1 - t, t);

            nt.normalize();
            expected.setToRotateAxis(nt, at);
            actual = quat2.mySlerp(quat1, t);
            TestUtil.COMPARE(expected.x, actual.x);
            TestUtil.COMPARE(expected.y, actual.y);
            TestUtil.COMPARE(expected.z, actual.z);
            TestUtil.COMPARE(expected.w, actual.w);
        }
예제 #13
0
        //外周の頂点インデックスを取得。yが一番小さい点から時計周りで取得。
        public List <int> getOutlinePointIndices(LDPointList points)
        {
            List <int> result = new List <int>();

            // 外周をたどる。始点に戻ったら終了。
            int startIndex = math.PointUtil.findMinYPointIndex(points);

            Debug.Assert(startIndex >= 0);

            result.Add(startIndex);

            int lastIndex    = -1;
            int currentIndex = startIndex;

            for (int i = 0; i < points.length(); ++i)
            {
                //現在の頂点と接続される点一覧を取得し、その中から進行方向に対してもっとも左側に位置するものを取得
                List <int> related = getRelatedPointIndices(currentIndex);

                LDPoint lastPoint;
                LDPoint currentPoint = points[currentIndex];
                if (lastIndex == -1)
                {
                    lastPoint = currentPoint - new LDPoint(0, 1);
                }
                else
                {
                    lastPoint = points[lastIndex];
                }


                int    nextIndex = -1;
                double minAngle  = 360;
                foreach (var targetIndex in related)
                {
                    LDPoint targetPoint = points[targetIndex];
                    if (targetIndex == lastIndex)
                    {
                        continue;
                    }
                    LDVector2 v1 = new LDVector2(lastPoint - currentPoint);
                    LDVector2 v2 = new LDVector2(targetPoint - currentPoint);

                    double angle = LDMathUtil.getAngle(v2, v1);
                    if (angle < minAngle)
                    {
                        minAngle  = angle;
                        nextIndex = targetIndex;
                    }
                }

                if (nextIndex == startIndex)
                {
                    //一周した
                    break;
                }
                result.Add(nextIndex);

                lastIndex    = currentIndex;
                currentIndex = nextIndex;
            }

            return(result);
        }
예제 #14
0
        public void extendedTransformTest()
        {
            {
                //拡張したGridの取得
                LDGridTransform src = new LDGridTransform(20, 20, 40, 40, 3, 3);
                LDGridTransform dst = src.createExtendedGrid();

                TestUtil.COMPARE(dst.getRow(), 4);
                TestUtil.COMPARE(dst.getColumn(), 4);
                TestUtil.COMPARE(dst.getPoint(0, 0), new LDPoint(-20, -20));
                TestUtil.COMPARE(dst.getPoint(0, 1), new LDPoint(10, -20));
                TestUtil.COMPARE(dst.getPoint(0, 2), new LDPoint(40, -20));
                TestUtil.COMPARE(dst.getPoint(0, 3), new LDPoint(70, -20));
                TestUtil.COMPARE(dst.getPoint(0, 4), new LDPoint(100, -20));
                TestUtil.COMPARE(dst.getPoint(1, 1), new LDPoint(20, 20));
            }

            {
                //範囲外 順変換 クリッピング
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 1, 1);
                LDPoint         src  = new LDPoint(-1, -1);

                LDPoint dst;

                dst = grid.transform(src, true);

                TestUtil.COMPARE(dst.x(), 20.0);
                TestUtil.COMPARE(dst.y(), 20.0);
            }
            {
                //範囲外 順変換
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 1, 1);
                LDPoint         src  = new LDPoint(-1, -1);

                LDPoint dst;

                dst = grid.transform(src);

                TestUtil.COMPARE(dst.x(), -20.0);
                TestUtil.COMPARE(dst.y(), -20.0);
            }
            {
                //範囲外 順変換
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 1, 1);
                LDPoint         src  = new LDPoint(-10, -10);

                LDPoint dst;

                dst = grid.transform(src);

                TestUtil.COMPARE(dst.x(), -380.0);
                TestUtil.COMPARE(dst.y(), -380.0);
            }
            {
                //範囲外 逆変換 クリッピング
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 2, 2);
                LDPoint         src  = new LDPoint(-20, -20);

                LDPoint dst;

                dst = grid.inverseTransform(src, true);

                TestUtil.COMPARE(dst.x(), 0.0);
                TestUtil.COMPARE(dst.y(), 0.0);
            }
            {
                //範囲外 逆変換
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 2, 2);
                LDPoint         src  = new LDPoint(-20, -20);

                LDPoint dst;

                dst = grid.inverseTransform(src);

                TestUtil.COMPARE(dst.x(), -1.0);
                TestUtil.COMPARE(dst.y(), -1.0);
            }

            {
                LDGridTransform grid = new LDGridTransform(
                    new LDPoint(20.53125f, 20.62423f)
                    , new  LDPoint(40.53125f, 20.62423f)
                    , new  LDPoint(45.53125f, 45.62423f)
                    , new LDPoint(20.614312f, 40.94645f), 2, 2);
                LDGridTransform src = new LDGridTransform(3425.0134623f, 2412.9143f, 5252 - 2412.090023f, 5212 - 2451.00001f, 2, 8);

                LDGridTransform dst = src;

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
            {
                LDGridTransform grid = new LDGridTransform(
                    new LDPoint(2012.53125f, 2051.62423f)
                    , new LDPoint(4097.53125f, 2033.62423f)
                    , new LDPoint(4575.53125f, 4566.62423f)
                    , new LDPoint(2062.614312f, 4000.94645f), 2, 2);
                LDGridTransform src = new LDGridTransform(34.0134623f, 24.9143f, 52 - 24.090023f, 52 - 24.00001f, 8, 2);

                LDGridTransform dst = src;

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
        }
예제 #15
0
        public void inverseTransformTest()
        {
            {
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 2, 2);
                LDPoint         src  = new LDPoint(30, 30);

                LDPoint dst = new LDPoint();

                dst = grid.inverseTransform(src);

                TestUtil.COMPARE(dst.x(), 0.25);
                TestUtil.COMPARE(dst.y(), 0.25);
            }

            {
                LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 2, 2);
                LDPointList     src  = new LDPointList();
                src.add(new LDPoint(30, 30)).add(new LDPoint(50, 50));

                LDPointList dst;

                dst = grid.inverseTransform(src);

                TestUtil.COMPARE(dst[0], new LDPoint(0.25f, 0.25f));
                TestUtil.COMPARE(dst[1], new LDPoint(0.75f, 0.75f));
            }

            /*
             * {
             *  LDGridTransform grid = new LDGridTransform(20, 20, 40, 40, 2, 2);
             *  LDGridTransform src = new LDGridTransform(24, 24, 52 - 24, 52 - 24, 2, 2);
             *
             *  LDGridTransform dst = src;
             *
             *  var points = grid.inverseTransform(src.toForm());
             *
             *
             *  dst.setForm(points);
             *  LDFUZZY_COMPARE(dst.getPoint(0, 0).x(), 0.1f, 0.0000001f);
             *  LDFUZZY_COMPARE(dst.getPoint(2, 2).x(), 0.8f, 0.0000001f);
             *  LDFUZZY_COMPARE(dst.getPoint(2, 0).x(), 0.1f, 0.0000001f);
             *  LDFUZZY_COMPARE(dst.getPoint(2, 0).y(), 0.8f, 0.0000001f);
             * }
             */
            {
                LDGridTransform grid = new LDGridTransform(20.53125f, 20.62423f, 40.614312f, 40.94645f, 2, 2);
                LDGridTransform src  = new LDGridTransform(24.0134623f, 24.9143f, 52 - 24.090023f, 52 - 24.00001f, 2, 2);

                LDGridTransform dst = new LDGridTransform(src);

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
            {
                LDGridTransform grid = new LDGridTransform(2530.53125f, 2540.62423f, 4015.614312f, 4026.94645f, 2, 2);
                LDGridTransform src  = new LDGridTransform(2594.0134623f, 2594.9143f, 5274 - 2594.090023f, 5276 - 2594.00001f, 2, 2);

                LDGridTransform dst = new LDGridTransform(src);

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
            {
                LDGridTransform grid = new LDGridTransform(
                    new LDPoint(20.53125f, 20.62423f)
                    , new LDPoint(40.53125f, 20.62423f)
                    , new LDPoint(45.53125f, 45.62423f)
                    , new LDPoint(20.614312f, 40.94645f), 2, 2);
                LDGridTransform src = new LDGridTransform(34.0134623f, 24.9143f, 52 - 24.090023f, 52 - 24.00001f, 8, 8);

                LDGridTransform dst = new LDGridTransform(src);

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
            {
                LDGridTransform grid = new LDGridTransform(
                    new LDPoint(2012.53125f, 2051.62423f)
                    , new LDPoint(4097.53125f, 2033.62423f)
                    , new LDPoint(4575.53125f, 4566.62423f)
                    , new LDPoint(2062.614312f, 4000.94645f), 2, 2);
                LDGridTransform src = new LDGridTransform(3444.0134623f, 2442.9143f, 5242 - 2412.090023f, 5211 - 2467.00001f, 8, 8);

                LDGridTransform dst = new LDGridTransform(src);

                var points = grid.inverseTransform(src.toForm());
                var rest   = grid.transform(points);

                dst.setForm(points);
                TestUtil.VERIFY(LDMathUtil.fuzzyCompare(rest, src.toForm(), 0.0000001f));
            }
        }