Example #1
0
        private void Build(VectorTileFeature feature, Rect rect, Texture2D height, GameObject parent, Tile.Parameters parameters)
        {
            foreach (var geometry in feature.GeometryAsWgs84((ulong)parameters.Id.Z, (ulong)parameters.Id.X, (ulong)parameters.Id.Y))
            {
                var meshData = new MeshData();
                //we'll run all visualizers on MeshData here
                var list = geometry.Select(wgs84 => GM.LatLonToMeters(wgs84.Lat, wgs84.Lng).ToVector3xz()).ToList();
                meshData.Vertices = list.Select(vertex =>
                {
                    var cord = vertex - rect.center.ToVector3xz();
                    var rx   = (vertex.x - rect.min.x) / rect.width;
                    var ry   = 1 - (vertex.z - rect.min.y) / rect.height;

                    var h = height == null ? 0 : GetHeightFromColor(height.GetPixel(
                                                                        (int)Mathf.Clamp((rx * 256), 0, 255),
                                                                        (int)Mathf.Clamp((ry * 256), 0, 255)));
                    cord.y += h;

                    return(cord);
                }).ToList();

                foreach (var mod in Modifiers)
                {
                    mod.Run(feature, meshData);
                }

                CreateGameObject(meshData, parent);
            }
        }
Example #2
0
        private void ParseLabelLayerToList(List <GOParsedLayer> list, VectorTile vt, GOLabelsLayer layer)
        {
            string[] lyrs = tile.GetLabelsStrings().Split(',');
//			string kindKey = tile.GetPoisKindKey();

            foreach (string l in lyrs)
            {
                VectorTileLayer lyr = vt.GetLayer(l);
                if (lyr != null)
                {
                    int featureCount = lyr.FeatureCount();

                    if (featureCount == 0)
                    {
                        continue;
                    }

                    GOParsedLayer pl = new GOParsedLayer();
                    pl.name        = lyr.Name;
                    pl.labelsLayer = layer;
                    pl.goFeatures  = new List <GOFeature> ();

                    for (int i = 0; i < featureCount; i++)
                    {
                        VectorTileFeature vtf        = lyr.GetFeature(i);
                        IDictionary       properties = vtf.GetProperties();

                        List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0);

                        if (geomWgs.Count == 0 || geomWgs[0].Count <= 1)
                        {
                            continue;
                        }

                        GOFeature gf = new GOFeature();
                        gf.properties    = properties;
                        gf.goFeatureType = vtf.GOFeatureType(geomWgs);
                        gf.labelsLayer   = layer;
                        gf.featureIndex  = (Int64)i + vt.LayerNames().IndexOf(lyr.Name);
                        gf.goTile        = goTile;
                        gf = tile.EditLabelData(gf);
                        gf.goFeatureType = GOFeatureType.Label;

                        gf.ConvertAttributes();
                        if (geomWgs.Count > 0)
                        {
                            gf.geometry = geomWgs[0];
                            gf.ConvertGeometries();
                            gf.preloadedLabelData = GOSegment.FindTheLongestStreightSegment(gf.convertedGeometry, 0);
                            AddFatureToList(gf, pl.goFeatures);
                        }
                    }
                    list.Add(pl);
                }
            }
        }
Example #3
0
        private void ParsePOILayerToList(List <GOParsedLayer> list, VectorTile vt, GOPOILayer layer)
        {
            string[] lyrs    = tile.GetPoisStrings().Split(',');
            string   kindKey = tile.GetPoisKindKey();

            foreach (string l in lyrs)
            {
                VectorTileLayer lyr = vt.GetLayer(l);
                if (lyr != null)
                {
                    int featureCount = lyr.FeatureCount();

                    if (featureCount == 0)
                    {
                        continue;
                    }

                    GOParsedLayer pl = new GOParsedLayer();
                    pl.name       = lyr.Name;
                    pl.poiLayer   = layer;
                    pl.goFeatures = new List <GOFeature> ();

                    for (int i = 0; i < featureCount; i++)
                    {
                        VectorTileFeature vtf        = lyr.GetFeature(i);
                        IDictionary       properties = vtf.GetProperties();

                        GOPOIKind      kind      = GOEnumUtils.PoiKindToEnum((string)properties[kindKey]);
                        GOPOIRendering rendering = layer.GetRenderingForPoiKind(kind);

                        if (kind == GOPOIKind.UNDEFINED || rendering == null)
                        {
                            continue;
                        }

                        List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0);
                        GOFeature             gf      = new GOFeature();
                        gf.poiKind       = kind;
                        gf.goTile        = goTile;
                        gf.properties    = properties;
                        gf.attributes    = GOFeature.PropertiesToAttributes(gf.properties);
                        gf.goFeatureType = vtf.GOFeatureType(geomWgs);

                        if (gf.goFeatureType == GOFeatureType.Undefined)
                        {
                            continue;
                        }

                        gf.poiLayer     = layer;
                        gf.poiRendering = rendering;
                        gf.featureIndex = (Int64)i + vt.LayerNames().IndexOf(lyr.Name);
                        gf = tile.EditFeatureData(gf);
                        gf.ConvertAttributes();

                        if (geomWgs.Count > 0 && gf.goFeatureType == GOFeatureType.Point)
                        {
                            gf.geometry = geomWgs [0];
                            gf.ConvertPOIGeometries();
                            AddFatureToList(gf, pl.goFeatures);
                        }
                    }

                    list.Add(pl);
                }
            }
        }
Example #4
0
        private void ParseGOLayerToList(List <GOParsedLayer> list, VectorTile vt, GOLayer layer)
        {
            string[] lyrs = tile.GetLayersStrings(layer).Split(',');

            foreach (string l in lyrs)
            {
                VectorTileLayer lyr = vt.GetLayer(l);
                if (lyr != null)
                {
                    int featureCount = lyr.FeatureCount();

                    if (featureCount == 0)
                    {
                        continue;
                    }

                    GOParsedLayer pl = new GOParsedLayer();
                    pl.name       = lyr.Name;
                    pl.goLayer    = layer;
                    pl.goFeatures = new List <GOFeature> ();

                    int indexOfLayer = vt.LayerNames().IndexOf(lyr.Name);

                    for (int i = 0; i < featureCount; i++)
                    {
                        VectorTileFeature vtf = lyr.GetFeature(i);

                        List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0);

                        GOFeature gf;
                        if (layer.layerType == GOLayer.GOLayerType.Roads)
                        {
                            gf = new GORoadFeature();
                        }
                        else
                        {
                            gf = new GOFeature();
                        }

                        gf.properties    = vtf.GetProperties();
                        gf.attributes    = GOFeature.PropertiesToAttributes(gf.properties);
                        gf.goFeatureType = vtf.GOFeatureType(geomWgs);
                        gf.layer         = layer;
                        gf.featureIndex  = (Int64)i;
                        gf.layerIndex    = indexOfLayer;
                        gf.featureCount  = featureCount;
                        gf        = tile.EditFeatureData(gf);
                        gf.goTile = goTile;
//							gf.setRenderingOptions ();
                        gf.ConvertAttributes();

                        if (geomWgs.Count > 0)
                        {
                            switch (gf.goFeatureType)
                            {
                            case GOFeatureType.Line:
                                gf.geometry = geomWgs [0];
                                gf.ConvertGeometries();
                                AddFatureToList(gf, pl.goFeatures);
                                break;

                            case GOFeatureType.Polygon:
                                gf.geometry = geomWgs[0];
                                gf.ConvertGeometries();
                                AddFatureToList(gf, pl.goFeatures);
                                break;

                            case GOFeatureType.MultiLine:
                                foreach (IList geometry in geomWgs)
                                {
                                    float     indexMulti = (((float)geomWgs.IndexOf((List <LatLng>)geometry) + 1) * (i + 1) / geomWgs.Count);
                                    GOFeature gfm;
                                    if (layer.layerType == GOLayer.GOLayerType.Roads)
                                    {
                                        gfm = new GORoadFeature((GORoadFeature)gf);
                                    }
                                    else
                                    {
                                        gfm = new GOFeature(gf);
                                    }

//									gfm.index = indexMulti;
                                    gfm.geometry = geometry;
                                    gfm.ConvertGeometries();
                                    AddFatureToList(gfm, pl.goFeatures);
                                }
                                break;

                            case GOFeatureType.MultiPolygon:
                                foreach (IList geometry in geomWgs)
                                {
                                    List <Vector3>         convertedSubject = null;
                                    List <List <Vector3> > convertedClips   = new List <List <Vector3> >();

                                    for (int j = 0; j < geomWgs.Count; j++)                                     //Clip ascending

                                    {
                                        IList          p          = geomWgs [j];
                                        List <Vector3> convertedP = GOFeature.CoordsToVerts(p, layer.layerType == GOLayer.GOLayerType.Buildings);
                                        if (GOFeature.IsClockwise(convertedP))
                                        {
                                            convertedSubject = convertedP;
                                        }
                                        else
                                        {
                                            //Add clip
                                            convertedClips.Add(convertedP);
                                        }
                                        //Last one
                                        if (j == geomWgs.Count - 1 || (j < geomWgs.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs [j + 1]) && convertedSubject != null))
                                        {
                                            GOFeature gfm = new GOFeature(gf);
//											gfm.index = (i +1)*j;
                                            gfm.convertedGeometry = convertedSubject;
                                            gfm.clips             = convertedClips;
                                            AddFatureToList(gfm, pl.goFeatures);

                                            convertedSubject = null;
                                            convertedClips   = new List <List <Vector3> >();
                                        }
                                    }
                                }
                                break;
                            }
                        }
                    }

                    if (goTile.combineFeatures)
                    {
                        pl = GOCombineFeatures.Combine(pl);
                    }

                    list.Add(pl);
                }
            }
        }
Example #5
0
 public VectorFeatureUnity(VectorTileFeature feature, UnityTile tile)
 {
     Data       = feature;
     Properties = Data.GetProperties();
     Points     = feature.GeometryAsWgs84((ulong)tile.Zoom, (ulong)tile.TileCoordinate.x, (ulong)tile.TileCoordinate.y);
 }
Example #6
0
        /// <summary>
        ///     Return the whole vector tile as GeoJSON
        /// </summary>
        /// <param name="tile"></param>
        /// <param name="zoom">Zoom level of the tile</param>
        /// <param name="tileColumn">Column of the tile (OSM tile schema)</param>
        /// <param name="tileRow">Row of the tile (OSM tile schema)</param>
        /// <param name="clipBuffer">
        ///     <para>Vector tiles may contain data reaching beyond the actual tile border.</para>
        ///     <para>Define if/how this data should be included.</para>
        ///     <para>'null': data from the vector tile as is</para>
        ///     <para>'&gt;=0': clip distance in internal tile units</para>
        /// </param>
        /// <returns>GeoJSON of the vector tile contents</returns>
        public static string ToGeoJson(
            this VectorTileObj tile
            , ulong zoom
            , ulong tileColumn
            , ulong tileRow
            , uint?clipBuffer = null
            )
        {
            //to get '.' instead of ',' when using "string.format" with double/float and non-US system number format settings
            //CultureInfo en_US = new CultureInfo("en-US");

            // escaping '{' '}' -> @"{{" "}}"
            //escaping '"' -> @""""
            string templateFeatureCollection = @"{{""type"":""FeatureCollection"",""features"":[{0}]}}";
            string templateFeature           =
                @"{{""type"":""Feature"",""geometry"":{{""type"":""{0}"",""coordinates"":[{1}]}},""properties"":{2}}}";

            var geojsonFeatures = new List <string>();

            foreach (string layerName in tile.LayerNames())
            {
                VectorTileLayer layer = tile.GetLayer(layerName);

                for (int i = 0; i < layer.FeatureCount(); i++)
                {
                    VectorTileFeature feat = layer.GetFeature(i, clipBuffer);

                    if (feat.GeometryType == GeomType.UNKNOWN)
                    {
                        continue;
                    }

                    //resolve properties
                    var keyValue = new List <string>();
                    int tagCnt   = feat.Tags.Count;
                    for (int j = 0; j < tagCnt; j += 2)
                    {
                        string key = layer.Keys[feat.Tags[j]];
                        object val = layer.Values[feat.Tags[j + 1]];
                        keyValue.Add(string.Format(NumberFormatInfo.InvariantInfo, @"""{0}"":""{1}""", key, val));
                    }

                    //build geojson properties object from resolved properties
                    string geojsonProps = string.Format(
                        NumberFormatInfo.InvariantInfo
                        , @"{{""id"":{0},""lyr"":""{1}""{2}{3}}}"
                        , feat.Id
                        , layer.Name
                        , keyValue.Count > 0 ? "," : ""
                        , string.Join(",", keyValue.ToArray())
                        );

                    //work through geometries
                    string geojsonCoords = "";
                    string geomType      = feat.GeometryType.Description();

                    //multipart
                    List <List <LatLng> > geomWgs84 = feat.GeometryAsWgs84(zoom, tileColumn, tileRow);
                    if (geomWgs84.Count > 1)
                    {
                        switch (feat.GeometryType)
                        {
                        case GeomType.POINT:
                            geomType      = "MultiPoint";
                            geojsonCoords = string.Join(
                                ","
                                , geomWgs84
                                .SelectMany(g => g)
                                .Select(g =>
                                        string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat))
                                .ToArray()
                                );
                            break;

                        case GeomType.LINESTRING:
                            geomType = "MultiLineString";
                            var parts = new List <string>();
                            foreach (List <LatLng> part in geomWgs84)
                            {
                                parts.Add("[" + string.Join(
                                              ","
                                              , part.Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray()
                                              ) + "]");
                            }

                            geojsonCoords = string.Join(",", parts.ToArray());
                            break;

                        case GeomType.POLYGON:
                            geomType = "MultiPolygon";
                            var partsMP = new List <string>();
                            foreach (List <LatLng> part in geomWgs84)
                            {
                                partsMP.Add("[" + string.Join(
                                                ",",
                                                part.Select(g => string.Format(NumberFormatInfo.InvariantInfo,
                                                                               "[{0},{1}]", g.Lng, g.Lat)).ToArray()
                                                ) + "]");
                            }

                            geojsonCoords = "[" + string.Join(",", partsMP.ToArray()) + "]";
                            break;
                        }
                    }
                    else if (geomWgs84.Count == 1)
                    {
                        //singlepart
                        switch (feat.GeometryType)
                        {
                        case GeomType.POINT:
                            geojsonCoords = string.Format(NumberFormatInfo.InvariantInfo, "{0},{1}",
                                                          geomWgs84[0][0].Lng, geomWgs84[0][0].Lat);
                            break;

                        case GeomType.LINESTRING:
                            geojsonCoords = string.Join(
                                ",",
                                geomWgs84[0].Select(g =>
                                                    string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat))
                                .ToArray()
                                );
                            break;

                        case GeomType.POLYGON:
                            geojsonCoords = "[" + string.Join(
                                ",",
                                geomWgs84[0].Select(g =>
                                                    string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]",
                                                                  g.Lng, g.Lat)).ToArray()
                                ) + "]";
                            break;
                        }
                    }
                    else
                    {
                        //no geometry
                        continue;
                    }

                    geojsonFeatures.Add(
                        string.Format(
                            NumberFormatInfo.InvariantInfo
                            , templateFeature
                            , geomType
                            , geojsonCoords
                            , geojsonProps
                            )
                        );
                }
            }

            string geoJsonFeatColl = string.Format(
                NumberFormatInfo.InvariantInfo
                , templateFeatureCollection
                , string.Join(",", geojsonFeatures.ToArray())
                );

            return(geoJsonFeatColl);
        }
Example #7
0
        private void ParseTilesetsToList(List <GOParsedLayer> list, VectorTile vt, GOTilesetLayer[] tilesets)
        {
            foreach (GOTilesetLayer tileSet in tilesets)
            {
                string kind = string.IsNullOrEmpty(tileSet.TilesetKindProperty)? tileSet.TilesetKindProperty : "kind";

                VectorTileLayer lyr = vt.GetLayer(tileSet.TilesetName);
                if (lyr != null)
                {
                    int featureCount = lyr.FeatureCount();

                    if (featureCount == 0)
                    {
                        continue;
                    }

                    GOParsedLayer pl = new GOParsedLayer();
                    pl.name         = lyr.Name;
                    pl.tilesetLayer = tileSet;
                    pl.goFeatures   = new List <GOFeature>();

                    for (int i = 0; i < featureCount; i++)
                    {
                        VectorTileFeature vtf = lyr.GetFeature(i);

                        List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0);
                        GOFeature             gf      = new GOFeature();

                        gf.properties    = vtf.GetProperties();
                        gf.attributes    = GOFeature.PropertiesToAttributes(gf.properties);
                        gf.goFeatureType = vtf.GOFeatureType(geomWgs);
                        gf.tileSetKind   = kind;
                        gf.tilesetLayer  = tileSet;
                        gf.goTile        = goTile;
                        gf.featureIndex  = (Int64)i;
                        //gf.layerIndex = indexOfLayer;
                        gf.featureCount = featureCount;
                        //gf = tile.EditFeatureData(gf);
                        gf.goTile = goTile;
                        gf.ConvertAttributes();

                        if (gf.goFeatureType == GOFeatureType.Undefined)
                        {
                            continue;
                        }

                        string name = "Dataset " + gf.goFeatureType.ToString();
                        //Debug.Log(name);

                        if (geomWgs.Count > 0 && (gf.goFeatureType == GOFeatureType.Point || gf.goFeatureType == GOFeatureType.MultiPoint)) //Probably needs a fix for multi points
                        {
                            //GOPOIKind kind = GOEnumUtils.PoiKindToEnum((string)properties[kindKey]);
                            GOTilesetPOIRendering rendering = tileSet.TilesetPOIRenderingForKind(kind);
                            if (rendering == null)
                            {
                                continue;
                            }

                            gf.geometry            = geomWgs[0];
                            gf.tileSetPoiRendering = rendering;
                            gf.name = name;
                            gf.ConvertPOIGeometries();
                            AddFatureToList(gf, pl.goFeatures);
                        }

                        else if (geomWgs.Count > 0)
                        {
                            switch (gf.goFeatureType)
                            {
                            case GOFeatureType.Line:
                                GOTilesetLINERendering lineRendering = tileSet.TilesetLINERenderingForKind(kind);
                                if (lineRendering == null)
                                {
                                    continue;
                                }
                                gf.geometry = geomWgs[0];
                                gf.ConvertGeometries();
                                gf.tileSetLineRendering = lineRendering;
                                gf.name   = name;
                                gf.height = lineRendering.height;
                                AddFatureToList(gf, pl.goFeatures);
                                break;

                            case GOFeatureType.Polygon:

                                GOTilesetPOLYGONRendering polygonRendering = tileSet.TilesetPOLYGONRenderingForKind(kind);
                                if (polygonRendering == null)
                                {
                                    continue;
                                }
                                gf.geometry = geomWgs[0];
                                gf.ConvertGeometries();
                                gf.name = name;
                                gf.tileSetPolygonRendering = polygonRendering;
                                gf.height = polygonRendering.height;
                                AddFatureToList(gf, pl.goFeatures);
                                break;

                            case GOFeatureType.MultiLine:
                                lineRendering = tileSet.TilesetLINERenderingForKind(kind);
                                if (lineRendering == null)
                                {
                                    continue;
                                }
                                foreach (IList geometry in geomWgs)
                                {
                                    float     indexMulti = (((float)geomWgs.IndexOf((List <LatLng>)geometry) + 1) * (i + 1) / geomWgs.Count);
                                    GOFeature gfm        = new GOFeature(gf);
                                    gf.name      = name;
                                    gfm.geometry = geometry;
                                    gfm.ConvertGeometries();
                                    gf.tileSetLineRendering = lineRendering;
                                    gf.height = lineRendering.height;
                                    AddFatureToList(gfm, pl.goFeatures);
                                }
                                break;

                            case GOFeatureType.MultiPolygon:
                                foreach (IList geometry in geomWgs)
                                {
                                    polygonRendering = tileSet.TilesetPOLYGONRenderingForKind(kind);
                                    if (polygonRendering == null)
                                    {
                                        continue;
                                    }
                                    List <Vector3>         convertedSubject = null;
                                    List <List <Vector3> > convertedClips   = new List <List <Vector3> >();

                                    for (int j = 0; j < geomWgs.Count; j++)
                                    {     //Clip ascending
                                        IList          p          = geomWgs[j];
                                        List <Vector3> convertedP = GOFeature.CoordsToVerts(p, false);
                                        if (GOFeature.IsClockwise(convertedP))
                                        {
                                            convertedSubject = convertedP;
                                        }
                                        else
                                        {
                                            //Add clip
                                            convertedClips.Add(convertedP);
                                        }
                                        //Last one
                                        if (j == geomWgs.Count - 1 || (j < geomWgs.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs[j + 1]) && convertedSubject != null))
                                        {
                                            GOFeature gfm = new GOFeature(gf);
                                            //											gfm.index = (i +1)*j;
                                            gfm.convertedGeometry      = convertedSubject;
                                            gfm.clips                  = convertedClips;
                                            gf.tileSetPolygonRendering = polygonRendering;
                                            gf.name = name;
                                            AddFatureToList(gfm, pl.goFeatures);
                                            convertedSubject = null;
                                            convertedClips   = new List <List <Vector3> >();
                                        }
                                    }
                                }
                                break;
                            }
                        }
                    }

                    list.Add(pl);
                }
            }
        }
Example #8
0
        public IEnumerator BuildLayer(VectorTileLayer layerData, GOLayer layer, bool delayedLoad)
        {
            GameObject parent = null;

            if (transform.FindChild(layer.name) == null)
            {
                parent                  = new GameObject();
                parent.name             = layer.name;
                parent.transform.parent = this.transform;
                parent.SetActive(!layer.startInactive);
            }
            else
            {
                parent = transform.FindChild(layer.name).gameObject;
            }


            if (layerData.FeatureCount() == 0)
            {
                yield break;
            }


            List <GOFeature> stack = new List <GOFeature> ();

            for (int i = 0; i < layerData.FeatureCount(); i++)
            {
                //get the feature
                VectorTileFeature feature   = layerData.GetFeature(i);
                GOFeature         goFeature = ParseFeatureData(feature, layer);

                if (layer.useOnly.Length > 0 && !layer.useOnly.Contains(goFeature.kind))
                {
                    continue;
                }
                if (layer.avoid.Length > 0 && layer.avoid.Contains(goFeature.kind))
                {
                    continue;
                }

                if (layer.layerType == GOLayer.GOLayerType.Roads)
                {
                    GORoadFeature grf = (GORoadFeature)goFeature;
                    if ((grf.isBridge && !layer.useBridges) || (grf.isTunnel && !layer.useTunnels) || (grf.isLink && !layer.useBridges))
                    {
                        continue;
                    }
                }

                //multipart
                List <List <LatLng> > geomWgs84 = feature.GeometryAsWgs84((ulong)map.zoomLevel, (ulong)tileCoordinates.x, (ulong)tileCoordinates.y, 0);

                string type = feature.GetFeatureType(geomWgs84);
                if (type == null || feature.GeometryType == GeomType.POINT)
                {
                    continue;
                }
                if (feature.GeometryType == GeomType.POLYGON && layer.layerType == GOLayer.GOLayerType.Roads)
                {
                    continue;
                }

                if (type == "MultiLineString" || (type == "Polygon" && !layer.isPolygon))
                {
                    foreach (IList geometry in geomWgs84)
                    {
                        GOFeature gf = ParseFeatureData(feature, layer);
                        gf.geometry   = geometry;
                        gf.type       = type;
                        gf.layer      = layer;
                        gf.parent     = parent;
                        gf.properties = feature.GetProperties();
                        gf.ConvertGeometries();
                        gf.ConvertAttributes();
                        gf.index         = (Int64)i;
                        gf.goFeatureType = GOFeature.GOFeatureType.MultiLine;
                        stack.Add(gf);
                    }
                }
                else if (type == "LineString")
                {
                    GOFeature gf = ParseFeatureData(feature, layer);
                    gf.geometry   = geomWgs84 [0];
                    gf.type       = type;
                    gf.layer      = layer;
                    gf.parent     = parent;
                    gf.properties = feature.GetProperties();
                    gf.ConvertGeometries();
                    gf.ConvertAttributes();
                    gf.index         = (Int64)i;
                    gf.goFeatureType = GOFeature.GOFeatureType.Line;
                    if (geomWgs84.Count == 0)
                    {
                        continue;
                    }

                    stack.Add(gf);
                }

                else if (type == "Polygon")
                {
                    GOFeature gf = ParseFeatureData(feature, layer);
                    gf.geometry   = geomWgs84 [0];
                    gf.type       = type;
                    gf.layer      = layer;
                    gf.parent     = parent;
                    gf.properties = feature.GetProperties();
                    gf.ConvertGeometries();
                    gf.ConvertAttributes();
                    gf.index         = (Int64)i;
                    gf.goFeatureType = GOFeature.GOFeatureType.Polygon;

                    stack.Add(gf);
                }

                else if (type == "MultiPolygon")
                {
                    GameObject multi = new GameObject("MultiPolygon");
                    multi.transform.parent = parent.transform;

                    IList subject = null;
                    IList clips   = new List <List <LatLng> >();

                    for (int j = 0; j < geomWgs84.Count; j++)                     //Clip ascending

                    {
                        IList p = geomWgs84 [j];
                        if (GOFeature.IsGeoPolygonClockwise(p))
                        {
                            subject = p;
                        }
                        else
                        {
                            //Add clip
                            clips.Add(p);
                        }
                        //Last one
                        if (j == geomWgs84.Count - 1 || (j < geomWgs84.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs84 [j + 1]) && subject != null))
                        {
                            GOFeature gf = ParseFeatureData(feature, layer);
                            gf.geometry   = subject;
                            gf.clips      = clips;
                            gf.type       = type;
                            gf.layer      = layer;
                            gf.parent     = parent;
                            gf.properties = feature.GetProperties();
                            gf.ConvertGeometries();
                            gf.ConvertAttributes();
                            gf.index         = (Int64)i;
                            gf.goFeatureType = GOFeature.GOFeatureType.MultiPolygon;

                            stack.Add(gf);

                            subject = null;
                            clips   = new List <List <LatLng> >();
                        }
                    }
                }
            }

            IList iStack = (IList)stack;

            if (layer.layerType == GOLayer.GOLayerType.Roads)
            {
                iStack = GORoadFeature.MergeRoads(iStack);
            }

            int n = 25;

            for (int i = 0; i < iStack.Count; i += n)
            {
                for (int k = 0; k < n; k++)
                {
                    if (i + k >= iStack.Count)
                    {
                        yield return(null);

                        break;
                    }

                    GOFeature   r       = (GOFeature)iStack [i + k];
                    IEnumerator routine = r.BuildFeature(this, delayedLoad);
                    if (routine != null)
                    {
                        if (Application.isPlaying)
                        {
                            StartCoroutine(routine);
                        }
                        else
                        {
                            GORoutine.start(routine, this);
                        }
                    }
                }
                yield return(new WaitForSeconds(0.5f));
            }

            Resources.UnloadUnusedAssets();

            yield return(null);
        }