private Rect generateCroppingRect(BBox bbox)
        {
            Geography geo = new Geography();

            Vector2 mintileCoord = new Vector2();
            Vector2 maxtileCoord = new Vector2();

            FindTiles(bbox, ref mintileCoord, ref maxtileCoord);

            float  left, bottom, right, top;
            double res = geo.Resolution(zoomLevel);

            left  = (float)Math.Round((bbox.meterLeft + geo.originShift) / res) - (mintileCoord.x * tileSize);
            right = (float)Math.Round((bbox.meterRight + geo.originShift) / res) - (mintileCoord.x * tileSize);

            bottom = (float)Math.Round((-bbox.meterBottom + geo.originShift) / res) - (maxtileCoord.y * tileSize);
            top    = (float)Math.Round((-bbox.meterTop + geo.originShift) / res) - (maxtileCoord.y * tileSize);

            Rect croppingRect = new Rect(left, top, right - left, bottom - top);

            return(croppingRect);
        }
        public myTerrain(HeightmapLoader _heightmap, BBox _bbox, string _OSMfileName, MapProvider _provider)
        {
            OSMfileName = _OSMfileName;
            heightmap = _heightmap;
            scenebbox = _bbox;
            textureType = _provider;

            terrainObject = new GameObject("Terrain");
            gridList = new List<GameObject>();

            int leftIndex = (int)Math.Floor((scenebbox.left - (float)Math.Floor(scenebbox.left)) * 1200.0f);
            int rightIndex = (int)Math.Ceiling((scenebbox.right - (float)Math.Floor(scenebbox.right)) * 1200.0f);

            if ((rightIndex - leftIndex) % 2 != 0)
                rightIndex++;

            int topIndex, bottomIndex;

            topIndex = (int)Math.Floor(((float)Math.Ceiling(scenebbox.top) - scenebbox.top) * 1200.0f);
            bottomIndex = (int)Math.Ceiling(((float)Math.Ceiling(scenebbox.bottom) - scenebbox.bottom) * 1200.0f);

            if ((bottomIndex - topIndex) % 2 != 0)
                topIndex -= 1;

            Debug.Log("<color=yellow>TERRAIN:</color>" + "left:" + leftIndex + " right:" + rightIndex
                       + " bottom:" + bottomIndex + " top:" + topIndex);

            float[,] myTerrainHeights = new float[1 + bottomIndex - topIndex, 1 + rightIndex - leftIndex ];
            Vector2[,] meterPositions = new Vector2[1 + bottomIndex - topIndex, 1 + rightIndex - leftIndex ];
            Geography geo = new Geography();

            float left = (float)Math.Floor(scenebbox.left) + (leftIndex / 1200.0f);
            float right = (float)Math.Floor(scenebbox.left) + (rightIndex / 1200.0f);
            float top = (float)Math.Ceiling(scenebbox.top) - (topIndex / 1200.0f);
            float bottom = (float)Math.Ceiling(scenebbox.top) - (bottomIndex / 1200.0f);

            for (int i = 0; i <= bottomIndex - topIndex; i++)
            {
                for (int j = 0; j <= rightIndex - leftIndex; j++)
                {
                    myTerrainHeights[i, j] = heightmap.heightmap[topIndex + i, leftIndex + j];
                    meterPositions[i , j] =  geo.LatLontoMeters(top - (i / 1200.0f), left + (j / 1200.0f));
                }
            }

            terrainInfo.leftIndex = leftIndex;
            terrainInfo.rightIndex = rightIndex;
            terrainInfo.bottomIndex = bottomIndex;
            terrainInfo.topIndex = topIndex;
            terrainInfo.terrainHeights = myTerrainHeights;
            terrainInfo.meterPositions = meterPositions;
            terrainInfo.ColumnCount = 1 + rightIndex - leftIndex;
            terrainInfo.RowCount = 1 + bottomIndex - topIndex;

            terrainInfo.terrainBBox = new BBox();
            terrainInfo.terrainBBox.left = left;
            terrainInfo.terrainBBox.top = top;
            terrainInfo.terrainBBox.bottom = bottom;
            terrainInfo.terrainBBox.right = right;
            Vector2 bottmleft = geo.LatLontoMeters(bottom, left);
            Vector2 topright = geo.LatLontoMeters(top, right);
            terrainInfo.terrainBBox.meterBottom = bottmleft.x;
            terrainInfo.terrainBBox.meterLeft = bottmleft.y;
            terrainInfo.terrainBBox.meterTop = topright.x;
            terrainInfo.terrainBBox.meterRight = topright.y;

            terrainInfo.shiftX = scenebbox.meterLeft;
            terrainInfo.shiftZ = scenebbox.meterBottom;

            Debug.Log("<color=yellow>TERRAIN:</color> ColumnCount:" + terrainInfo.ColumnCount + " RowCount:" + terrainInfo.RowCount);

               // drawBoundsforDebug();

            for (int i = 0; i < terrainInfo.RowCount-1; i += 2)
            {
                for (int j = 0; j < terrainInfo.ColumnCount-1; j += 2)
                    createGrid(i,j);
            }

            drawUnderPlates();
        }
        private float HighPrecisionTerrainHeight(float meterx, float meterz, bool isLatlon)
        {
            double finalvalue = 0.0;

            Vector2 c;
            if (!isLatlon)
            {
                Geography proj = new Geography();
                c = proj.meterstoLatLonDouble(meterx, meterz);
            }
            else
            {
                c = new Vector2(meterx, meterz);
            }

            double ratioX = Math.Ceiling(scenebbox.top) - c.x;
            double ratioZ = c.y - Math.Floor(scenebbox.left);

            double Xindex = (1200.0 * ratioX);
            double Zindex = (1200.0 * ratioZ);

            //Upper Triangle
            if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) < 1.0f)
            {
                int n = heightmap.heightmap[(int)Math.Floor(Xindex), (int)Math.Ceiling(Zindex)];
                int m = heightmap.heightmap[(int)Math.Floor(Xindex), (int)Math.Floor(Zindex)];
                int k = heightmap.heightmap[(int)Math.Ceiling(Xindex), (int)Math.Floor(Zindex)];
                double interpolationUp = m + (n - m) * (Zindex - Math.Floor(Zindex));
                double interpolationHypothenus = k + (n - k) * (Zindex - Math.Floor(Zindex));

                double a = Xindex - Math.Floor(Xindex);
                double aplusb = Math.Ceiling(Zindex) - Zindex;
                finalvalue = interpolationUp + (interpolationHypothenus - interpolationUp) * (a / aplusb);

            }

            //Lower Triangle
            else if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) >= 1.0f)
            {

                int n = heightmap.heightmap[(int)Math.Ceiling(Xindex), (int)Math.Ceiling(Zindex)];
                int m = heightmap.heightmap[(int)Math.Ceiling(Xindex), (int)Math.Floor(Zindex)];
                int k = heightmap.heightmap[(int)Math.Floor(Xindex), (int)Math.Ceiling(Zindex)];
                double interpolationDown = m + (n - m) * (Zindex - Math.Floor(Zindex));
                double interpolationHypothenus = m + (k - m) * (Zindex - Math.Floor(Zindex));

                double a = Math.Ceiling(Xindex) - Xindex;
                double aplusb = Zindex - Math.Floor(Zindex);
                finalvalue = interpolationDown + (interpolationHypothenus - interpolationDown) * (a / aplusb);

                if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) > 0.99 && (Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) < 1.01)
                    return (float)interpolationHypothenus;

            }

            return (float)finalvalue;
        }
        private float getTerrainTriangleHeight(float meterx, float meterz)
        {
            float finalvalue = 0.0f;

            Geography proj = new Geography();
            Vector2 c = proj.meterstoLatLon(meterx, meterz);

            float ratioX = (float)Math.Ceiling(scenebbox.top) - c.x;
            float ratioZ = c.y - (float)Math.Floor(scenebbox.left);

            float Xindex = (1200.0f * ratioX);
            float Zindex = (1200.0f * ratioZ);

            //Upper Triangle
            if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) < 1.0f)
            {
                int n = heightmap.heightmap[(int)Math.Floor(Xindex),(int)Math.Ceiling(Zindex)];
                int m = heightmap.heightmap[(int)Math.Floor(Xindex),(int)Math.Floor(Zindex)];
                int k = heightmap.heightmap[(int)Math.Ceiling(Xindex),(int)Math.Floor(Zindex)];
                float interpolationUp = m + (n - m) * (Zindex - (float)Math.Floor(Zindex));
                float interpolationHypothenus = k + (n - k) * (Zindex - (float)Math.Floor(Zindex));

                float a = Xindex - (float)Math.Floor(Xindex);
                float aplusb = (float)Math.Ceiling(Zindex) - Zindex;
                finalvalue = interpolationUp + (interpolationHypothenus - interpolationUp) * (a / aplusb);

            }

            //Lower Triangle
            else if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) >= 1.0f)
            {

                int n = heightmap.heightmap[(int)Math.Ceiling(Xindex),(int)Math.Ceiling(Zindex)];
                int m = heightmap.heightmap[(int)Math.Ceiling(Xindex),(int)Math.Floor(Zindex)];
                int k = heightmap.heightmap[(int)Math.Floor(Xindex),(int)Math.Ceiling(Zindex)];
                float interpolationDown = m + (n - m) * (Zindex - (float)Math.Floor(Zindex));
                float interpolationHypothenus = m + (k - m) * (Zindex - (float)Math.Floor(Zindex));

                float a = (float)Math.Ceiling(Xindex) - Xindex;
                float aplusb = Zindex - (float)Math.Floor(Zindex);
                finalvalue = interpolationDown + (interpolationHypothenus - interpolationDown) * (a / aplusb);

                if ((Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) > 0.98f && (Xindex - Math.Floor(Xindex)) + (Zindex - Math.Floor(Zindex)) < 1.02f)
                    return interpolationHypothenus;

            }

            float final2 = HighPrecisionTerrainHeight(meterx, meterz,false);

            if (final2 - finalvalue !=  0.0f)
                Debug.Log("<color=red>PRECISION ERROR VAR</color>" + (final2-finalvalue).ToString("0.000"));

            return final2;
        }
        private Rect generateCroppingRect(BBox bbox)
        {
            Geography geo = new Geography();

            Vector2 mintileCoord = new Vector2();
            Vector2 maxtileCoord = new Vector2();
            FindTiles(bbox, ref mintileCoord, ref maxtileCoord);

            float left, bottom, right, top;
            double res = geo.Resolution(zoomLevel);

            left = (float)Math.Round((bbox.meterLeft + geo.originShift) / res) - (mintileCoord.x * tileSize);
            right = (float)Math.Round((bbox.meterRight + geo.originShift) / res) - (mintileCoord.x * tileSize);

            bottom = (float)Math.Round((-bbox.meterBottom + geo.originShift) / res) - (maxtileCoord.y * tileSize);
            top = (float)Math.Round((-bbox.meterTop + geo.originShift) / res) - (maxtileCoord.y * tileSize);

            Rect croppingRect = new Rect(left, top, right - left, bottom - top);

            return croppingRect;
        }
        private void FindTiles(BBox bbox, ref Vector2 mintileCoord, ref Vector2 maxtileCoord)
        {
            Geography geo = new Geography();

            mintileCoord = geo.MetersToTile(bbox.meterBottom,bbox.meterLeft,zoomLevel);
            maxtileCoord = geo.MetersToTile(bbox.meterTop, bbox.meterRight,zoomLevel);
        }