Esempio n. 1
0
 public string GetCachedTileFilePathName(TileInfo tileInfo)
 {
     return(Path.Combine(GetDirectoryName(tileInfo), string.Format(CultureInfo.InvariantCulture, "{0}.{1}", tileInfo.TileY, format.ToString())));
 }
Esempio n. 2
0
        /// <summary>
        /// Creates and Serves vector tiles
        /// </summary>
        /// <param name="boundVariables"></param>
        /// <param name="operationInput"></param>
        /// <param name="outputFormat"></param>
        /// <param name="requestProperties"></param>
        /// <param name="responseProperties"></param>
        /// <returns></returns>
        private byte[] VectorTileHandler(NameValueCollection boundVariables,
                                         JsonObject operationInput,
                                         string outputFormat,
                                         string requestProperties,
                                         out string responseProperties)
        {
            //responseProperties = null;
            responseProperties = null; //"Content-Type:application/json";
            ESRI.ArcGIS.SOESupport.AutoTimer timer = new AutoTimer();

            const string methodName = "VectorTileHandler";

            try
            {
                long?      layerIndex;
                long?      zoom;
                long?      row;
                long?      col;
                string     jsonFormatParam;
                TileFormat jsonFormat = TileFormat.EsriJson; // Defaulting to EsriJson
                if (!operationInput.TryGetAsLong("l", out layerIndex))
                {
                    throw new ArgumentNullException("layer");
                }
                if (!operationInput.TryGetAsLong("z", out zoom))
                {
                    throw new ArgumentNullException("zoom");
                }
                if (!operationInput.TryGetAsLong("y", out row))
                {
                    throw new ArgumentNullException("row");
                }
                if (!operationInput.TryGetAsLong("x", out col))
                {
                    throw new ArgumentNullException("col");
                }
                if (operationInput.TryGetString("jf", out jsonFormatParam))
                {
                    if (!string.IsNullOrEmpty(jsonFormatParam))
                    {
                        jsonFormatParam = jsonFormatParam.ToLower().Trim();
                        Enum.GetNames(typeof(TileFormat)).ToList().ForEach(n =>
                        {
                            if (n.ToLower() == jsonFormatParam)
                            {
                                jsonFormat = (TileFormat)Enum.Parse(typeof(TileFormat), jsonFormatParam, true);
                            }
                        });
                    }
                }


                //System.Diagnostics.Debug.WriteLine(string.Format("l:{0}, r:{1}, c:{2}", zoom, row, col));

                // Check to see if the tile exists on disk...
                //  <cache-root>\<layerId>\<zoom>\<row>\<col>.esrijson;
                //i.e. to be consistent with Esri tile caching structure
                string tilePath = string.Format(@"{0}\{1}\{2}\{3}\{4}.{5}",
                                                _vectorCacheRootDirectory, layerIndex, zoom.Value,
                                                row.Value, col.Value, jsonFormat.ToString().ToLower());
                if (File.Exists(tilePath))
                {
                    // Fetch tile contents from disk
                    _dtsLogger.LogInfo(soe_name, methodName, "Time: " + timer.Elapsed.ToString());
                    logger.LogMessage(ServerLogger.msgType.infoSimple, methodName, -1, "Time: " + timer.Elapsed.ToString());
                    return(this.ReadTileFile(tilePath));
                }
                else
                {
                    // Write new files to disk

                    IMapServer3 mapServer = serverObjectHelper.ServerObject as IMapServer3;
                    if (mapServer == null)
                    {
                        throw new InvalidOperationException("Unable to access the map server.");
                    }

                    // Get the bbox. Returns an envelope in WGS84 (4326).
                    IEnvelope env102100 = TileUtil.GetEnvelopeFromZoomRowCol((int)zoom.Value, (int)row.Value, (int)col.Value);
                    //_dtsLogger.LogInfo(soe_name, methodName, this.GeometryToXml(env4326));


                    // Convert envelope to polygon b/c QueryData does not support spatialfilter geometry using envelope
                    IPolygon polygon102100 = this.CreatePolygonFromEnvelope(env102100);

                    // Use QueryData and generalize result geometries based on zoom level
                    IQueryResultOptions resultOptions = new QueryResultOptionsClass();
                    // i.e; IRecordSet to support BOTH json and geojson
                    resultOptions.Format = esriQueryResultFormat.esriQueryResultRecordSetAsObject;
                    IMapTableDescription tableDescription =
                        this.GetTableDescription(mapServer, (int)layerIndex, (int)zoom);

                    // Create spatial filter
                    ISpatialFilter spatialFilter = new SpatialFilterClass();
                    spatialFilter.Geometry      = polygon102100;
                    spatialFilter.GeometryField = "Shape";
                    spatialFilter.SpatialRel    = esriSpatialRelEnum.esriSpatialRelIntersects;
                    //TODO:  Subfields should be configurable
                    spatialFilter.SubFields = "*";

                    // Execute query
                    IQueryResult result = mapServer.QueryData(mapServer.DefaultMapName,
                                                              tableDescription, spatialFilter, resultOptions);

                    byte[] json = null;

                    // TODO:  Support writing tiles for no data
                    // Need a way to do this for GeoJson; parse Esri JSON recordset into GeoJson
                    if (result == null || !this.RecordsetHasFeatures(result.Object as IRecordSet))
                    {
                        // Write "no data" tile
                        if (jsonFormat == TileFormat.EsriJson)
                        {
                            resultOptions.Format = esriQueryResultFormat.esriQueryResultJsonAsMime;
                            result = mapServer.QueryData(mapServer.DefaultMapName, tableDescription, spatialFilter, resultOptions);
                            json   = result.MimeData;
                        }
                        else
                        {
                            json = StrToByteArray(NO_DATA_GEOJSON);
                        }
                    }
                    else
                    {
                        //We have features...
                        IRecordSet features = result.Object as IRecordSet;

                        // Get geometry type for query layer
                        esriGeometryType geometryType = this.GetLayerGeometryType(mapServer.GetServerInfo(mapServer.DefaultMapName).MapLayerInfos, (int)layerIndex);
                        switch (geometryType)
                        {
                        case esriGeometryType.esriGeometryPoint:
                            // Do nothing... already intersected
                            json = ESRI.ArcGIS.SOESupport.Conversion.ToJson(features);
                            break;

                        case esriGeometryType.esriGeometryPolyline:
                            // Polylines must be clipped to envelope
                            IFeatureCursor cursor = null;
                            this.ClipFeaturesToTile(ref cursor, ref features, env102100);
                            json = ESRI.ArcGIS.SOESupport.Conversion.ToJson(features);
                            this.ReleaseComObject(cursor);
                            break;

                        case esriGeometryType.esriGeometryMultipoint:
                        case esriGeometryType.esriGeometryPolygon:
                            // Get IDs of features whose centroid is contained by tile envelope
                            List <int> ids = this.GetIdsOfContainedFeatureCentroids(features, polygon102100);
                            if (ids.Count == 0)
                            {
                                // Write no data tile
                                if (jsonFormat == TileFormat.EsriJson)
                                {
                                    // Query to get empty featureset and serialize to disk
                                    resultOptions.Format = esriQueryResultFormat.esriQueryResultJsonAsMime;
                                    IQueryFilter queryFilter = new QueryFilterClass();
                                    queryFilter.SubFields   = "*";
                                    queryFilter.WhereClause = "1=2";
                                    result = mapServer.QueryData(mapServer.DefaultMapName, tableDescription, queryFilter, resultOptions);
                                    json   = result.MimeData;
                                }
                                else
                                {
                                    json = StrToByteArray(NO_DATA_GEOJSON);
                                }
                            }
                            else
                            {
                                // Execute new query for IDs
                                IQueryFilter queryFilter = new QueryFilterClass();
                                queryFilter.SubFields = "*";
                                // TODO:  Account for sql query syntax based on datasource
                                //      FGDB/Shapefile then "OBJECTID"; quotes required
                                //      PGDB then [OBJECTID]; brackets required
                                //      SDE then OBJECTID; nothing but the fieldname
                                queryFilter.WhereClause = string.Format("\"OBJECTID\" IN({0})", ids.ToDelimitedString <int>(","));    // FGDB
                                result   = mapServer.QueryData(mapServer.DefaultMapName, tableDescription, queryFilter, resultOptions);
                                features = result.Object as IRecordSet;
                                // Do some checking here...
                                var featureCount = this.GetRecordsetFeatureCount(features);
                                if (featureCount != ids.Count)
                                {
                                    System.Diagnostics.Debug.WriteLine(string.Format("Query Problem:  ID search results IS NOT EQUAL to contained IDs count - [{0}:{1}]", featureCount, ids.Count));
                                    System.Diagnostics.Debug.WriteLine("Query:  " + queryFilter.WhereClause);
                                }
                                json = ESRI.ArcGIS.SOESupport.Conversion.ToJson(features);
                            }

                            break;


                        default:
                            throw new NotSupportedException(string.Format("Geometry type {0} is not supported by {1}", geometryType.ToString(), soe_name));
                        }
                    }


                    //store the json to disk
                    this.WriteTileFile(json, tilePath, (int)layerIndex, (int)zoom, (int)row);
                    _dtsLogger.LogInfo(soe_name, methodName, "Time: " + timer.Elapsed.ToString());
                    logger.LogMessage(ServerLogger.msgType.infoSimple, methodName, -1, "Time: " + timer.Elapsed.ToString());
                    return(json);
                }
            }
            catch (Exception ex)
            {
                // Log the error
                _dtsLogger.LogError(soe_name, methodName, "n/a", ex);
                logger.LogMessage(ServerLogger.msgType.error, methodName, 9999, ex.StackTrace);
                return(StrToByteArray("{}"));
            }
        }